Включите корпоративный WeChat для получения сообщений + проверьте правильность URL-адреса
Включите корпоративный WeChat для получения сообщений + проверьте правильность URL-адреса

Включите корпоративный WeChat для получения сообщений + проверьте правильность URL-адреса

📔 Введение в «Краткие заметки Цяньсюня»

тысячи заметок были выложены в открытый доступ,GiteeиGitHubпоискchihiro-notes,Содержит исходные файлы заметок.md,И PDF-версия для удобного чтения.,И да использует красивую тему,Лучший опыт чтения,Если статья полезна для вас, пожалуйста, нажмите на нее для меня.Star

возобновлять:Поддержка чтения статей онлайн,Классифицированы по дате выпуска.

@toc

Введение

Предварительная подготовка

  • Зарегистрированное доменное имя.
  • Приложения, которые можно развернуть онлайн, соответствуют доменным именам.

2.3 Источником используемого примера кода является Enterprise WeChat-Центр разработчиков.

Документация по открытию и получению информации в Enterprise WeChat

Язык кода:javascript
копировать
https://developer.work.weixin.qq.com/document/10514

Ключевые слова этой статьи

Предприятие Вичат Включите получение сообщенийПроверьте действительность URL-адресаSHA1Предоставляет интерфейс Расшифровать для получения и отправки сообщений Вичат предприятиям.Интерфейс расчета подписи сообщения

Этапы реализации

1 Включите получение сообщений

1.1 Настройка параметров получения сообщений

В серверной части управления предприятием введите целевое приложение, которое необходимо настроить для получения сообщений, нажмите кнопку «Настроить прием API» в разделе «Получение сообщений», чтобы войти на страницу конфигурации.

Используемые три параметра: URL, Token и EncodingAESKey.

  • Протокол доступа и адрес для серверной части URL-адреса предприятия для получения push-запроса корпоративного Вичата,Поддержка протокола http или https.
  • Токен может быть произвольно заполнен предприятием и использован для генерации подписей.
  • EncodingAESKeyдля тела сообщенияшифрование,Кодировка Base64 ключа даAES.

Эти три параметра необходимо использовать в следующем коде.

2. Проверьте правильность URL-адреса.

2.1 Официальное описание

При нажатии «Сохранить» для отправки вышеуказанной информации,Предприятие Вичат отправит подтверждающее сообщение на указанный URL.,Способ отправки:GET。 После того как принимающий сервер сообщений предприятия получит запрос на проверку, ему необходимо дать правильный ответ, чтобы пройти проверку URL-адреса.

Предположим, что адрес получателя сообщения установлен на:http://api.3dept.com/,Предприятие Вичат отправит на этот адрес следующий запрос на проверку:

Метод запроса: ПОЛУЧИТЬ Запросить адрес

Язык кода:javascript
копировать
http://api.3dept.com/?msg_signature=ASDFQWEXZCVAQFASDFASDFSS&timestamp=13500001234&nonce=123412323&echostr=ENCRYPT_STR

Описание параметра

параметр

должен

иллюстрировать

msg_signature

да

предприятие Вичатшифрованиезнак,msg_signature结合了предприятие填写的token、временная метка в запросе、nonceпараметр、шифрованиетело сообщения

timestamp

да

Временная метка

nonce

да

случайное число

echostr

да

Зашифрованная строка. Его необходимо расшифровать, чтобы получить простой текст содержимого сообщения. После расшифровки есть четыре поля: случайное, msg_len, msg и CorpID — это простой текст содержимого сообщения.

После того как серверная часть предприятия получит запрос, ей необходимо сделать следующее:

  1. Urlрасшифровать полученный запрос
  2. Проверьте запрос через параметрmsg_signature, чтобы подтвердить легитимность вызывающего абонента.
  3. Расшифроватьechostrпараметр Получить содержимое сообщения(Прямо сейчасmsgПоле)
  4. Вернуть содержимое обычного текстового сообщения в том виде, в каком оно есть в течение 1 секунды (без кавычек, без заголовка спецификации, без символа новой строки).
2.2 Java-код
Код слоя контроллера: **QYWeiXinLoginController.java**
Язык кода:javascript
копировать
package com.ruoyi.project.controller;


import com.ruoyi.project.tx.qyweixin.service.IQYWeiXinLoginService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


@RestController
@RequestMapping("/wechat/info")
public class QYWechatInfoController {

    @Resource
    private IQYWeiXinLoginService qyWeiXinLoginService;

    /**
     * Проверьте действительность URL-адреса
     *
     */
    @RequestMapping(value = "/verifyURLValidity", method = RequestMethod.GET)
    public void verifyURLValidity(@RequestParam(value = "msg_signature", required = true) String msgSignature,
                                  @RequestParam(value = "timestamp", required = true) String timestamp,
                                  @RequestParam(value = "nonce", required = true) String nonce,
                                  @RequestParam(value = "echostr", required = true) String echostr,
                                  HttpServletResponse response) {
        String msg = qyWeiXinLoginService.verifyURLValidity(msgSignature, timestamp, nonce, echostr);
        try {
            response.getWriter().print(msg);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

}
Бизнес-интерфейс:**IQYWeiXinLoginService.java**
Язык кода:javascript
копировать
package com.ruoyi.project.tx.qyweixin.service;


public interface IQYWeiXinLoginService {
    String verifyURLValidity(String msgSignature, String timestamp, String nonce, String echostr);
}
Реализация бизнес-интерфейса: **QYWeiXinLoginServiceImpl.java**
Язык кода:javascript
копировать
package com.ruoyi.project.tx.qyweixin.service.impl;


import com.ruoyi.project.tx.qyweixin.service.IQYWeiXinLoginService;
import com.ruoyi.project.utils.aes.AesException;
import com.ruoyi.project.utils.aes.WXBizMsgCrypt;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

@Service
public class QYWeiXinLoginServiceImpl implements IQYWeiXinLoginService {
    private static final Logger logger = LoggerFactory.getLogger(QYWeiXinLoginServiceImpl.class);

    @Override
    public String  verifyURLValidity(String msgSignature, String timestamp, String nonce, String echostr) {
        logger.info("параметр, полученный предприятием Вичат логин: msgSignature:{},timestamp:{},nonce:{},echostr:{}:",msgSignature,timestamp,nonce,echostr);
        //token
        String TOKEN = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
        // encodingAESKey
        String ENCODINGAES_KEY = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
        //Идентификатор предприятия
        String CORP_ID = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

        // Проверьте запрос, проверив msg_signature. Если проверка прошла успешно, echostr будет возвращен без изменений, что указывает на успешный доступ, в противном случае доступ завершится неудачно.
        String result = null;
        try {
            WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(TOKEN, ENCODINGAES_KEY, CORP_ID);
            result = wxcpt.VerifyURL(msgSignature, timestamp, nonce, echostr);
        } catch (AesException e) {
            e.printStackTrace();
        }
        logger.info("----------Доступ к интерфейсу Вичат окончен ----------");
        return result;
    }
}
2.3 Используемый пример кода
Предоставляет интерфейс шифрования и дешифрования для получения и отправки корпоративных сообщений WeChat: **WXBizMsgCrypt.java**
Язык кода:javascript
копировать
/**
 * Пример кода для шифрования и расшифровки сообщений, отправляемых предприятием на серверную часть предприятия.
 *
 * @copyright Copyright (c) 1998-2014 Tencent Inc.
 */

// ------------------------------------------------------------------------

/**
 * Для org.apache.commons.codec.binary.Base64:
 * Необходимо импортировать стоечный пакет commons-codec-1.9 (или commons-codec-1.8 и другие версии).
 * Официальный адрес загрузки: http://commons.apache.org/proper/commons-codec/download_codec.cgi.
 */
package com.ruoyi.project.utils.aes;

import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Random;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;

/**
 * Предоставляет интерфейс шифрования и дешифрования (строка в кодировке UTF8) для получения и отправки сообщений предприятиям.
 * <ol>
 *  <li>ответ третьей сторонышифрованиеинформация给предприятие Вичат</li>
 *  <li>第三方收到предприятие Вичатсообщение отправлено,Проверьте безопасность сообщения,и обработать сообщение Расшифровать。</li>
 * </ol>
 * иллюстрировать:аномальныйjava.security.InvalidKeyException:illegal Key Решение по размеру
 * <ol>
 *  <li>Скачать с официального сайтаJCEФайл политики неограниченных разрешений(JDK7скачать адрес:
 *      http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html</li>
 *  <li>Разархивируйте после загрузки,можно увидетьlocal_policy.jarиUS_export_policy.jarа такжеreadme.txt</li>
 *  <li>Если установленоJRE,поставь дваjarфайл в%JRE_HOME%\lib\securityПерезаписать исходные файлы в каталоге</li>
 *  <li>Если установленоJDK,поставь дваjarфайл в%JDK_HOME%\jre\lib\securityПерезаписать исходный файл в каталоге</li>
 * </ol>
 */
public class WXBizMsgCrypt {
    static Charset CHARSET = Charset.forName("utf-8");
    Base64 base64 = new Base64();
    byte[] aesKey;
    String token;
    String receiveid;

    /**
     * Конструктор
     * @param token Серверная часть Enterprise Вичат, токен, установленный разработчиками
     * @param encodingAesKey Фон Enterprise Вичат, EncodingAESKey установлен разработчиком
     * @param receiveid, Различные сценарии имеют разное значение, подробности см. в документации.
     *
     * @throws AesException Не удалось выполнить выполнение. Проверьте код ошибки и конкретную информацию об ошибке для исключения.
     */
    public WXBizMsgCrypt(String token, String encodingAesKey, String receiveid) throws AesException {
        if (encodingAesKey.length() != 43) {
            throw new AesException(AesException.IllegalAesKey);
        }

        this.token = token;
        this.receiveid = receiveid;
        aesKey = Base64.decodeBase64(encodingAesKey + "=");
    }

    // Сгенерировать 4 байта в сетевом порядке байтов.
    byte[] getNetworkBytesOrder(int sourceNumber) {
        byte[] orderBytes = new byte[4];
        orderBytes[3] = (byte) (sourceNumber & 0xFF);
        orderBytes[2] = (byte) (sourceNumber >> 8 & 0xFF);
        orderBytes[1] = (byte) (sourceNumber >> 16 & 0xFF);
        orderBytes[0] = (byte) (sourceNumber >> 24 & 0xFF);
        return orderBytes;
    }

    // Восстановить 4-байтовый порядок сетевых байтов
    int recoverNetworkBytesOrder(byte[] orderBytes) {
        int sourceNumber = 0;
        for (int i = 0; i < 4; i++) {
            sourceNumber <<= 8;
            sourceNumber |= orderBytes[i] & 0xff;
        }
        return sourceNumber;
    }

    // Случайно сгенерировать 16-значную строку
    String getRandomStr() {
        String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < 16; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }

    /**
     * Зашифровать открытый текст.
     *
     * @param text Обычный текст, который необходимо зашифровать
     * @return Зашифрованная строка в кодировке Base64
     * @throws AesException AES-шифрование не удалось
     */
    String encrypt(String randomStr, String text) throws AesException {
        ByteGroup byteCollector = new ByteGroup();
        byte[] randomStrBytes = randomStr.getBytes(CHARSET);
        byte[] textBytes = text.getBytes(CHARSET);
        byte[] networkBytesOrder = getNetworkBytesOrder(textBytes.length);
        byte[] receiveidBytes = receiveid.getBytes(CHARSET);

        // randomStr + networkBytesOrder + text + receiveid
        byteCollector.addBytes(randomStrBytes);
        byteCollector.addBytes(networkBytesOrder);
        byteCollector.addBytes(textBytes);
        byteCollector.addBytes(receiveidBytes);

        // ... + pad: Используйте собственный метод заполнения для заполнения обычного текста
        byte[] padBytes = PKCS7Encoder.encode(byteCollector.size());
        byteCollector.addBytes(padBytes);

        // Получите окончательный поток байтов, Не зашифровано
        byte[] unencrypted = byteCollector.toBytes();

        try {
            // Установите режим шифрования на режим CBC AES.
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
            IvParameterSpec iv = new IvParameterSpec(aesKey, 0, 16);
            cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);

            // шифрование
            byte[] encrypted = cipher.doFinal(unencrypted);

            // Используйте BASE64 для кодирования строки после шифрования.
            String base64Encrypted = base64.encodeToString(encrypted);

            return base64Encrypted;
        } catch (Exception e) {
            e.printStackTrace();
            throw new AesException(AesException.EncryptAESError);
        }
    }

    /**
     * Расшифруйте зашифрованный текст.
     *
     * @param text Зашифрованный текст, который необходимо расшифровать
     * @return Расшифрованный открытый текст
     * @throws AesException расшифровка aes не удалась
     */
    String decrypt(String text) throws AesException {
        byte[] original;
        try {
            // Установите режим дешифрования на режим AES CBC.
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            SecretKeySpec key_spec = new SecretKeySpec(aesKey, "AES");
            IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16));
            cipher.init(Cipher.DECRYPT_MODE, key_spec, iv);

            // Декодировать зашифрованный текст с помощью BASE64
            byte[] encrypted = Base64.decodeBase64(text);

            // Расшифровать
            original = cipher.doFinal(encrypted);
        } catch (Exception e) {
            e.printStackTrace();
            throw new AesException(AesException.DecryptAESError);
        }

        String xmlContent, from_receiveid;
        try {
            // Удалить символы заполнения
            byte[] bytes = PKCS7Encoder.decode(original);

            // Отдельная 16-битная случайная строка, порядок сетевых байтов и идентификатор получения.
            byte[] networkOrder = Arrays.copyOfRange(bytes, 16, 20);

            int xmlLength = recoverNetworkBytesOrder(networkOrder);

            xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), CHARSET);
            from_receiveid = new String(Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length),
                    CHARSET);
        } catch (Exception e) {
            e.printStackTrace();
            throw new AesException(AesException.IllegalBuffer);
        }

        // Когда полученный идентификатор отличается
        if (!from_receiveid.equals(receiveid)) {
            throw new AesException(AesException.ValidateCorpidError);
        }
        return xmlContent;

    }

    /**
     * 将предприятие Вичат Ответ на сообщение пользователяшифрование Пакет.
     * <ol>
     *  <li>对要сообщение отправлено进行AES-CBCшифрование</li>
     *  <li>Создать подпись безопасности</li>
     *  <li>отправит сообщениезашифрованный текстизащищенная подпись Пакет成xmlФормат</li>
     * </ol>
     *
     * @param replyMsg Сообщение предприятия, на которое пользователь должен ответить, строка в формате xml.
     * @param timeStamp Временная метка, вы можете сгенерировать ее самостоятельно или использовать временную метку параметра URL.
     * @param nonce Случайная строка, вы можете сгенерировать ее самостоятельно или использовать параметр nonce URL-адреса.
     *
     * @return шифрование может напрямую отвечать на зашифрованные сообщения пользователя. текст,Включает msg_signature, timestamp, nonce, зашифровать строку формата XML
     * @throws AesException Не удалось выполнить выполнение. Проверьте код ошибки и конкретную информацию об ошибке для исключения.
     */
    public String EncryptMsg(String replyMsg, String timeStamp, String nonce) throws AesException {
        // шифрование
        String encrypt = encrypt(getRandomStr(), replyMsg);

        // Создать подпись безопасности
        if (timeStamp == "") {
            timeStamp = Long.toString(System.currentTimeMillis());
        }

        String signature = SHA1.getSHA1(token, timeStamp, nonce, encrypt);

        // System.out.println("Подпись отправлена ​​на платформу: " + signature[1].toString());
        // Создать XML для отправки
        String result = XMLParse.generate(encrypt, signature, timeStamp, nonce);
        return result;
    }

    /**
     * Проверьте подлинность сообщения,и получить Расшифроватьобычный текст после.
     * <ol>
     *  <li>Используйте полученноезашифрованный текст Создать подпись безопасности,进行знак验证</li>
     *  <li>Если проверка пройдена,Затем извлекитеxmlвшифрованиеинформация</li>
     *  <li>对информация进行Расшифровать</li>
     * </ol>
     *
     * @param msgSignature Строка подписи, соответствующая msg_signature параметра URL.
     * @param timeStamp Временная метка, временная метка, соответствующая параметру URL.
     * @param nonce Случайная строка, соответствующая nonce параметра URL.
     * @param postData Шифрованный текст, соответствующий данным POST-запроса.
     *
     * @return Оригинальный текст после Расшифровать
     * @throws AesException Не удалось выполнить выполнение. Проверьте код ошибки и конкретную информацию об ошибке для исключения.
     */
    public String DecryptMsg(String msgSignature, String timeStamp, String nonce, String postData)
            throws AesException {

        // Ключ, приложение для общедоступной учетной записи secret
        // Извлечь зашифрованный текст
        Object[] encrypt = XMLParse.extract(postData);

        // Проверьте подпись безопасности
        String signature = SHA1.getSHA1(token, timeStamp, nonce, encrypt[1].toString());

        // Сравните с подписью в URL на предмет равенства.
        // System.out.println("Третья сторона получила подпись в URL:" + msg_sign);
        // System.out.println("Сторонняя проверочная подпись:" + signature);
        if (!signature.equals(msgSignature)) {
            throw new AesException(AesException.ValidateSignatureError);
        }

        // Расшифровать
        String result = decrypt(encrypt[1].toString());
        return result;
    }

    /**
     * URL-адрес подтверждения
     * @param msgSignature Строка подписи, соответствующая msg_signature параметра URL.
     * @param timeStamp Временная метка, временная метка, соответствующая параметру URL.
     * @param nonce Случайная строка, соответствующая nonce параметра URL.
     * @param echoStr Случайная строка, echostr, соответствующая параметру URL.
     *
     * @return Расшифроватьпослеechostr
     * @throws AesException Не удалось выполнить выполнение. Проверьте код ошибки и конкретную информацию об ошибке для исключения.
     */
    public String VerifyURL(String msgSignature, String timeStamp, String nonce, String echoStr)
            throws AesException {
        String signature = SHA1.getSHA1(token, timeStamp, nonce, echoStr);

        if (!signature.equals(msgSignature)) {
            throw new AesException(AesException.ValidateSignatureError);
        }

        String result = decrypt(echoStr);
        return result;
    }

}
Класс исключений шифрования и дешифрования: **AesException.java**
Язык кода:javascript
копировать
package com.ruoyi.project.utils.aes;

/**
 * добавлять Расшифроватьаномальный类
 */
public class AesException extends Exception {
    public final static int OK = 0;
    public final static int ValidateSignatureError = -40001;
    public final static int ParseXmlError = -40002;
    public final static int ComputeSignatureError = -40003;
    public final static int IllegalAesKey = -40004;
    public final static int ValidateCorpidError = -40005;
    public final static int EncryptAESError = -40006;
    public final static int DecryptAESError = -40007;
    public final static int IllegalBuffer = -40008;
//public final static int EncodeBase64Error = -40009;
//public final static int DecodeBase64Error = -40010;
//public final static int GenReturnXmlError = -40011;
    private int code;

    private static String getMessage(int code) {
        switch (code) {
            case ValidateSignatureError:
                return «Ошибка проверки подписи»;
            case ParseXmlError:
                return «Ошибка анализа XML»;
            case ComputeSignatureError:
                return "shaшифрование生成знак失败";
            case IllegalAesKey:
                return «SymmetricKey является незаконным»;
            case ValidateCorpidError:
                return «корпорированная проверка не удалась»;
            case EncryptAESError:
                return "AES-шифрование не удалось";
            case DecryptAESError:
                return "расшифровка aes не удалась";
            case IllegalBuffer:
                return «Буфер, полученный после Расшифровать, является незаконным»;
//      case EncodeBase64Error:
//          return "ошибка шифрования base64";
//      case DecodeBase64Error:
//          return "base64Расшифровать ошибку";
//      case GenReturnXmlError:
//          return «создание XML не удалось»;
            default:
                return null; // cannot be
        }
    }
    public int getCode() {
        return code;
    }
    AesException(int code) {
        super(getMessage(code));
        this.code = code;
    }
}

ByteGroup.java

Язык кода:javascript
копировать
package com.ruoyi.project.utils.aes;

import java.util.ArrayList;

class ByteGroup {
    ArrayList<Byte> byteContainer = new ArrayList<Byte>();

    public byte[] toBytes() {
        byte[] bytes = new byte[byteContainer.size()];
        for (int i = 0; i < byteContainer.size(); i++) {
            bytes[i] = byteContainer.get(i);
        }
        return bytes;
    }

    public ByteGroup addBytes(byte[] bytes) {
        for (byte b : bytes) {
            byteContainer.add(b);
        }
        return this;
    }

    public int size() {
        return byteContainer.size();
    }
}
Предоставляет интерфейс шифрования и дешифрования на основе алгоритма PKCS7: **PKCS7Encoder.java**
Язык кода:javascript
копировать
package com.ruoyi.project.utils.aes;

import java.nio.charset.Charset;
import java.util.Arrays;

/**
 * Предоставить на основеPKCS7算法的добавлять Расшифроватьинтерфейс.
 */
class PKCS7Encoder {
    static Charset CHARSET = Charset.forName("utf-8");
    static int BLOCK_SIZE = 32;

    /**
     * Получите байты, дополняющие открытый текст.
     *
     * @param count Количество байтов открытого текста, которые необходимо заполнить и дополнить.
     * @return Массив байтов для завершения
     */
    static byte[] encode(int count) {
        // Подсчитайте количество цифр для заполнения
        int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE);
        if (amountToPad == 0) {
            amountToPad = BLOCK_SIZE;
        }
        // Получить персонажа, используемого для заполнения позиции
        char padChr = chr(amountToPad);
        String tmp = new String();
        for (int index = 0; index < amountToPad; index++) {
            tmp += padChr;
        }
        return tmp.getBytes(CHARSET);
    }

    /**
     * Удалите дополнительные символы открытого текста после Расшифровать.
     *
     * @param decrypted Расшифроватьобычный текст после
     * @return Удалите простой текст после символов заполнения.
     */
    static byte[] decode(byte[] decrypted) {
        int pad = (int) decrypted[decrypted.length - 1];
        if (pad < 1 || pad > 32) {
            pad = 0;
        }
        return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad);
    }

    /**
     * Преобразование чисел в символы, соответствующие коду ASCII, используемые для дополнения обычного текста.
     *
     * @param a Числа, которые нужно преобразовать
     * @return Преобразованные символы
     */
    static char chr(int a) {
        byte target = (byte) (a & 0xFF);
        return (char) target;
    }

}
Интерфейс расчета подписи сообщения: **SHA1.java**
Язык кода:javascript
копировать
package com.ruoyi.project.utils.aes;

import java.security.MessageDigest;
import java.util.Arrays;
/**
 * Пример кода для шифрования и расшифровки сообщений, отправляемых предприятием на серверную часть предприятия.
 *
 * @copyright Copyright (c) 1998-2014 Tencent Inc.
 */
/**
 * SHA1 class
 *
 * Интерфейс вычисления подписи сообщения.
 */
public class SHA1 {

    /**
     * Использование алгоритма SHA1 Создать подпись безопасности
     * @param token счет
     * @param timestamp Временная метка
     * @param nonce случайная строка
     * @param encrypt зашифрованный текст
     * @return защищенная подпись
     * @throws AesException
     */
    public static String getSHA1(String token, String timestamp, String nonce, String encrypt) throws AesException
              {
        try {
            String[] array = new String[] { token, timestamp, nonce, encrypt };
            StringBuffer sb = new StringBuffer();
            // Сортировка строк
            Arrays.sort(array);
            for (int i = 0; i < 4; i++) {
                sb.append(array[i]);
            }
            String str = sb.toString();
            // Генерация подписи SHA1
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            md.update(str.getBytes());
            byte[] digest = md.digest();

            StringBuffer hexstr = new StringBuffer();
            String shaHex = "";
            for (int i = 0; i < digest.length; i++) {
                shaHex = Integer.toHexString(digest[i] & 0xFF);
                if (shaHex.length() < 2) {
                    hexstr.append(0);
                }
                hexstr.append(shaHex);
            }
            return hexstr.toString();
        } catch (Exception e) {
            e.printStackTrace();
            throw new AesException(AesException.ComputeSignatureError);
        }
    }
}
Предоставляет интерфейсы для извлечения зашифрованного текста в формате сообщения и создания формата ответного сообщения: **XMLParse.java**
Язык кода:java
копировать
/**
 * Пример кода для шифрования и расшифровки сообщений, отправляемых предприятием на серверную часть предприятия.
 *
 * @copyright Copyright (c) 1998-2014 Tencent Inc.
 */

// ------------------------------------------------------------------------

package com.ruoyi.project.utils.aes;

import java.io.StringReader;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

/**
 * XMLParse class
 *
 * 提供提取информация Форматвзашифрованный текст及生成回复информация Формат的интерфейс.
 */
class XMLParse {

    /**
     * извлекатьxml数据包вшифрованиеинформация
     * @param xmltext xml-строка, которую нужно извлечь
     * @return извлекать的шифрованиеинформация字符串
     * @throws AesException
     */
    public static Object[] extract(String xmltext) throws AesException     {
        Object[] result = new Object[3];
        try {
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

            String FEATURE = null;
            // This is the PRIMARY defense. If DTDs (doctypes) are disallowed, almost all XML entity attacks are prevented
            // Xerces 2 only - http://xerces.apache.org/xerces2-j/features.html#disallow-doctype-decl
            FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
            dbf.setFeature(FEATURE, true);

            // If you can't completely disable DTDs, then at least do the following:
            // Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-general-entities
            // Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-general-entities
            // JDK7+ - http://xml.org/sax/features/external-general-entities
            FEATURE = "http://xml.org/sax/features/external-general-entities";
            dbf.setFeature(FEATURE, false);

            // Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-parameter-entities
            // Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-parameter-entities
            // JDK7+ - http://xml.org/sax/features/external-parameter-entities
            FEATURE = "http://xml.org/sax/features/external-parameter-entities";
            dbf.setFeature(FEATURE, false);

            // Disable external DTDs as well
            FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
            dbf.setFeature(FEATURE, false);

            // and these as well, per Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks"
            dbf.setXIncludeAware(false);
            dbf.setExpandEntityReferences(false);

            // And, per Timothy Morgan: "If for some reason support for inline DOCTYPEs are a requirement, then
            // ensure the entity settings are disabled (as shown above) and beware that SSRF attacks
            // (http://cwe.mitre.org/data/definitions/918.html) and denial
            // of service attacks (such as billion laughs or decompression bombs via "jar:") are a risk."

            // remaining parser logic
            DocumentBuilder db = dbf.newDocumentBuilder();
            StringReader sr = new StringReader(xmltext);
            InputSource is = new InputSource(sr);
            Document document = db.parse(is);

            Element root = document.getDocumentElement();
            NodeList nodelist1 = root.getElementsByTagName("Encrypt");
            result[0] = 0;
            result[1] = nodelist1.item(0).getTextContent();
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            throw new AesException(AesException.ParseXmlError);
        }
    }

    /**
     * Создать XML-сообщение
     * @param encrypt шифрование后的информациязашифрованный текст
     * @param signature защищенная подпись
     * @param timestamp Временная метка
     * @param nonce случайная строка
     * @return Сгенерированная строка XML
     */
    public static String generate(String encrypt, String signature, String timestamp, String nonce) {

        String format = "<xml>\n" + "<Encrypt><![CDATA[%1$s]]></Encrypt>\n"
                + "<MsgSignature><![CDATA[%2$s]]></MsgSignature>\n"
                + "<TimeStamp>%3$s</TimeStamp>\n" + "<Nonce><![CDATA[%4$s]]></Nonce>\n" + "</xml>";
        return String.format(format, encrypt, signature, timestamp, nonce);

    }
}
boy illustration
Углубленный анализ переполнения памяти CUDA: OutOfMemoryError: CUDA не хватает памяти. Попыталась выделить 3,21 Ги Б (GPU 0; всего 8,00 Ги Б).
boy illustration
[Решено] ошибка установки conda. Среда решения: не удалось выполнить первоначальное зависание. Повторная попытка с помощью файла (графическое руководство).
boy illustration
Прочитайте нейросетевую модель Трансформера в одной статье
boy illustration
.ART Теплые зимние предложения уже открыты
boy illustration
Сравнительная таблица описания кодов ошибок Amap
boy illustration
Уведомление о последних правилах Points Mall в декабре 2022 года.
boy illustration
Даже новички могут быстро приступить к работе с легким сервером приложений.
boy illustration
Взгляд на RSAC 2024|Защита конфиденциальности в эпоху больших моделей
boy illustration
Вы используете ИИ каждый день и до сих пор не знаете, как ИИ дает обратную связь? Одна статья для понимания реализации в коде Python общих функций потерь генеративных моделей + анализ принципов расчета.
boy illustration
Используйте (внутренний) почтовый ящик для образовательных учреждений, чтобы использовать Microsoft Family Bucket (1T дискового пространства на одном диске и версию Office 365 для образовательных учреждений)
boy illustration
Руководство по началу работы с оперативным проектом (7) Практическое сочетание оперативного письма — оперативного письма на основе интеллектуальной системы вопросов и ответов службы поддержки клиентов
boy illustration
[docker] Версия сервера «Чтение 3» — создайте свою собственную программу чтения веб-текста
boy illustration
Обзор Cloud-init и этапы создания в рамках PVE
boy illustration
Корпоративные пользователи используют пакет регистрационных ресурсов для регистрации ICP для веб-сайта и активации оплаты WeChat H5 (с кодом платежного узла версии API V3)
boy illustration
Подробное объяснение таких показателей производительности с высоким уровнем параллелизма, как QPS, TPS, RT и пропускная способность.
boy illustration
Удачи в конкурсе Python Essay Challenge, станьте первым, кто испытает новую функцию сообщества [Запускать блоки кода онлайн] и выиграйте множество изысканных подарков!
boy illustration
[Техническая посадка травы] Кровавая рвота и отделка позволяют вам необычным образом ощипывать гусиные перья! Не распространяйте информацию! ! !
boy illustration
[Официальное ограниченное по времени мероприятие] Сейчас ноябрь, напишите и получите приз
boy illustration
Прочтите это в одной статье: Учебник для няни по созданию сервера Huanshou Parlu на базе CVM-сервера.
boy illustration
Cloud Native | Что такое CRD (настраиваемые определения ресурсов) в K8s?
boy illustration
Как использовать Cloudflare CDN для настройки узла (CF самостоятельно выбирает IP) Гонконг, Китай/Азия узел/сводка и рекомендации внутреннего высокоскоростного IP-сегмента
boy illustration
Дополнительные правила вознаграждения амбассадоров акции в марте 2023 г.
boy illustration
Можно ли открыть частный сервер Phantom Beast Palu одним щелчком мыши? Супер простой урок для начинающих! (Прилагается метод обновления сервера)
boy illustration
[Играйте с Phantom Beast Palu] Обновите игровой сервер Phantom Beast Pallu одним щелчком мыши
boy illustration
Maotouhu делится: последний доступный внутри страны адрес склада исходного образа Docker 2024 года (обновлено 1 декабря)
boy illustration
Кодирование Base64 в MultipartFile
boy illustration
5 точек расширения SpringBoot, супер практично!
boy illustration
Глубокое понимание сопоставления индексов Elasticsearch.
boy illustration
15 рекомендуемых платформ разработки с нулевым кодом корпоративного уровня. Всегда найдется та, которая вам понравится.
boy illustration
Аннотация EasyExcel позволяет экспортировать с сохранением двух десятичных знаков.