1. Введение
В последнее время я забрасывал оплату WeChat, и сертификат довольно раздражает, поэтому необходимо поделиться некоторым опытом, чтобы уменьшить ваше наступление на яму при разработке оплаты WeChat. В настоящее время API оплаты WeChat был разработан дляV3версия в популярном стиле Restful.
Сегодня давайте поделимся сложностями оплаты WeChat -подписать, хотя есть много полезных SDK, но если вы хотите глубже понять оплату WeChat, вам все равно нужно это понять.
2. Сертификат API
Чтобы обеспечить безопасность конфиденциальных данных о средствах, мы обеспечиваем надежность операций с денежными средствами в нашем бизнесе. В настоящее время предоставляется в официальном сертификате CA (сертификате API), выданном третьей стороной WeChat Pay.закрытый ключподписывать.Через торговую платформу вы можете настроить и получить сертификаты API..
Помните, что вам будет предложено скачать, когда вы устанавливаете его в первый раз, и загрузка не будет предоставлена позже, пожалуйста, обратитесь к конкретной инструкции.
нашел после установкиzip
Разархивируйте сжатый пакет, в нем много файлов, только нужно обратить внимание на разработку JAVAapiclient_cert.p12
Этот файл сертификата подойдет, он содержит公私钥
, нам нужно положить его на сервер и разобрать с помощью Java.p12
файл, чтобы получить открытый ключ и закрытый ключ.
Обязательно обеспечить безопасность сертификата на стороне сервера, это предполагает безопасность средств.
Разобрать сертификат API
Следующим шагом является анализ сертификата.Методов анализа сертификата в интернете много.Здесь я использую более "обычный" метод анализа,используя пакет безопасности JDK.java.security.KeyStore
Разрешить.
Используется сертификат платежного API WeChatPKCS12
алгоритм, проходимKeyStore
получить носитель пары открытый-закрытый ключKeyPair
и серийный номер сертификатаserialNumber
, я инкапсулировал класс инструмента:
import org.springframework.core.io.ClassPathResource;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
/**
* KeyPairFactory
*
* @author dax
* @since 13:41
**/
public class KeyPairFactory {
private KeyStore store;
private final Object lock = new Object();
/**
* 获取公私钥.
*
* @param keyPath the key path
* @param keyAlias the key alias
* @param keyPass password
* @return the key pair
*/
public KeyPair createPKCS12(String keyPath, String keyAlias, String keyPass) {
ClassPathResource resource = new ClassPathResource(keyPath);
char[] pem = keyPass.toCharArray();
try {
synchronized (lock) {
if (store == null) {
synchronized (lock) {
store = KeyStore.getInstance("PKCS12");
store.load(resource.getInputStream(), pem);
}
}
}
X509Certificate certificate = (X509Certificate) store.getCertificate(keyAlias);
certificate.checkValidity();
// 证书的序列号 也有用
String serialNumber = certificate.getSerialNumber().toString(16).toUpperCase();
// 证书的 公钥
PublicKey publicKey = certificate.getPublicKey();
// 证书的私钥
PrivateKey storeKey = (PrivateKey) store.getKey(keyAlias, pem);
return new KeyPair(publicKey, storeKey);
} catch (Exception e) {
throw new IllegalStateException("Cannot load keys from store: " + resource, e);
}
}
}
Видно, что это модифицированная версия метода извлечения открытого и закрытого ключей, используемого в JWT в учебнике Spring Security от Fat Brother, Вы можете сравнить различия.
В этом методе есть три параметра, которые необходимо объяснить здесь:
-
keyPath
сертификат APIapiclient_cert.p12
изclasspath
путь, как правило, мы будем ставитьresources
В пути, конечно, вы можете изменить способ получения входного потока сертификата. -
keyAlias
Псевдоним сертификата, этого документа WeChat не существует, толстый брат получил значение DEBUG при загрузке сертификата, и значение зафиксировано какTenpay Certificate
. -
keyPass
Пароль сертификата, значение по умолчанию является бизнес-номер, в других конфигурациях также требуетсяmchid
, ты используешьсупер администраторСтрока цифр в вашем профиле для входа в WeChat Merchant Platform.
3. Подпись V3
Версия WeChat Pay V3Сигнатура заключается в том, что когда мы вызываем конкретный API WeChat Pay, мы переносим определенную строку кода в заголовок HTTP-запроса для сервера WeChat Pay, чтобы проверить источник запроса, чтобы убедиться, что запрос является подлинным.
Формат подписи
Конкретный формат строки подписи, всего пять строк и одна строка не может быть меньше, каждая строка отделяется символом новой строки\n
конец.
HTTP请求方法\n
URL\n
请求时间戳\n
请求随机串\n
请求报文主体\n
-
Метод HTTP-запросаМетод запроса, требуемый API-интерфейсом оплаты WeChat, который вы вызываете, например, платеж APP,
POST
. -
URLНапример, платежный документ APP
https://api.mch.weixin.qq.com/v3/pay/transactions/app
, удалите часть имени домена, чтобы получить URL-адрес, участвующий в подписи. Если в запросе есть параметры запроса, '?' и соответствующая строка запроса должны быть добавлены в конец URL-адреса. здесь для/v3/pay/transactions/app
. -
Запросить временную меткуОтметка системного времени сервера гарантирует, что время сервера правильное и используется.
System.currentTimeMillis() / 1000
Возьми. -
запросить случайную строкуНайдите класс инструментов для создания подобных
593BEC0C930BF1AFEB40B4A08C8FB242
Строка подойдет. -
тело сообщения запросаеслиGETзапрос непосредственно нанулевой символ
""
; когда метод запросаPOST
илиPUT
, пожалуйста, используйтеОтправить реальностьизJSON
сообщение. API загрузки изображений, пожалуйста, используйтеmeta
соответствующийJSON
сообщение.
Создать подпись
Затем мы используем пару закрытых ключей продавца в формате выше.Строка для подписиВыполните SHA256 с подписью RSA и выполните результат подписи.Кодировка Base64Получите значение подписи. Соответствующий основной код Java:
/**
* V3 SHA256withRSA 签名.
*
* @param method 请求方法 GET POST PUT DELETE 等
* @param canonicalUrl 例如 https://api.mch.weixin.qq.com/v3/pay/transactions/app?version=1 ——> /v3/pay/transactions/app?version=1
* @param timestamp 当前时间戳 因为要配置到TOKEN 中所以 签名中的要跟TOKEN 保持一致
* @param nonceStr 随机字符串 要和TOKEN中的保持一致
* @param body 请求体 GET 为 "" POST 为JSON
* @param keyPair 商户API 证书解析的密钥对 实际使用的是其中的私钥
* @return the string
*/
@SneakyThrows
String sign(String method, String canonicalUrl, long timestamp, String nonceStr, String body, KeyPair keyPair) {
String signatureStr = Stream.of(method, canonicalUrl, String.valueOf(timestamp), nonceStr, body)
.collect(Collectors.joining("\n", "", "\n"));
Signature sign = Signature.getInstance("SHA256withRSA");
sign.initSign(keyPair.getPrivate());
sign.update(signatureStr.getBytes(StandardCharsets.UTF_8));
return Base64Utils.encodeToString(sign.sign());
}
4. Используйте подпись
После того, как подпись будет сгенерирована, она будет объединена с некоторыми параметрами для формированияToken
размещается в соответствующем HTTP-запросеAuthorization
В заголовке запроса формат такой:
Authorization: WECHATPAY2-SHA256-RSA2048 {Token}
Token
Он состоит из следующих пяти частей:
-
Идентификатор продавца, инициировавшего запрос (включая продавцов с прямым подключением, поставщиков услуг или продавцов каналов)
mchid
-
Сертификат API продавцасерийный номер
serial_no
, дляОбъявляет используемый сертификат -
запросить случайную строку
nonce_str
-
отметка времени
timestamp
-
Значение подписи
signature
Token
Сгенерированный основной код:
/**
* 生成Token.
*
* @param mchId 商户号
* @param nonceStr 随机字符串
* @param timestamp 时间戳
* @param serialNo 证书序列号
* @param signature 签名
* @return the string
*/
String token(String mchId, String nonceStr, long timestamp, String serialNo, String signature) {
final String TOKEN_PATTERN = "mchid=\"%s\",nonce_str=\"%s\",timestamp=\"%d\",serial_no=\"%s\",signature=\"%s\"";
// 生成token
return String.format(TOKEN_PATTERN,
wechatPayProperties.getMchId(),
nonceStr, timestamp, serialNo, signature);
}
будет генерироватьToken
Подпись можно использовать, поместив ее в заголовок запроса в соответствии с указанным выше форматом.
5. Резюме
В этой статье мы провели полный анализ сложных подписей и использования подписей в WeChat Pay V 3. В то же время мы также объяснили анализ сертификатов API, которые, я считаю, могут помочь вам решить некоторые конкретные проблемы в развитие оплаты. Когда у меня будет время позже, я объясню проверку подписи, обратите внимание на:Код Фермер Маленький Толстый БратСвоевременный доступ к серии знаний.
关注公众号:Felordcn获取更多资讯