> Java > Java베이스 > 본문

Java에서의 WeChat 결제에 대한 자세한 설명(1): API V3 버전 서명

coldplay.xixi
풀어 주다: 2020-10-27 17:20:21
앞으로
2426명이 탐색했습니다.

Java 기본 튜토리얼 칼럼에서는 WeChat 결제를 Java로 소개하고 API V3 버전 서명을 구현합니다.

Java에서의 WeChat 결제에 대한 자세한 설명(1): API V3 버전 서명

1. 소개

최근 WeChat 결제에 어려움을 겪고 있는데 인증서가 여전히 꽤 짜증스럽기 때문에 WeChat 결제를 개발할 때 함정을 줄이기 위해 몇 가지 경험을 공유해야 합니다. 현재 WeChat 결제 API는 대중적인 Restful 스타일을 채택하여 V3 버전으로 개발되었습니다.

Java에서의 WeChat 결제에 대한 자세한 설명(1): API V3 버전 서명

오늘은 WeChat 결제 - Signature의 어려움을 공유하겠습니다. 유용한 SDK가 많지만 WeChat 결제를 깊이 이해하려면 그래도 이해해야 합니다.

2. API 인증서

민감한 금융 데이터의 보안을 보장하고 비즈니스의 금융 거래가 완벽하게 이루어지도록 보장합니다. 현재 위챗페이는 제3자가 발급한 신뢰할 수 있는 CA 인증서(API 인증서)에서 제공하는 개인 키를 서명용으로 사용하고 있습니다. 판매자 플랫폼을 통해 API 인증서를 설정하고 얻을 수 있습니다.

Java에서의 WeChat 결제에 대한 자세한 설명(1): API V3 버전 서명

처음 설정할 때 다운로드하라는 메시지가 표시된다는 점을 기억하세요. 자세한 내용은 더 이상 다운로드가 제공되지 않습니다.

Java에서의 WeChat 결제에 대한 자세한 설명(1): API V3 버전 서명说明

설정 후 zip压缩包解压,里面有很多文件,对于JAVA开发来说只需要关注apiclient_cert.p12这个证书文件就行了,它包含了公私钥,我们需要把它放在服务端并利用Java解析.p12 파일을 찾아 공개키와 개인키를 받으세요.

금융적인 보안과 관련된 서버 측 인증서의 보안을 반드시 보장하세요.

API 인증서 구문 분석

다음 단계는 인증서를 구문 분석하는 것입니다. 인터넷에서 인증서를 구문 분석하는 방법에는 java.security를 ​​사용하여 보다 "공식적인" 방법을 사용합니다. JDK 보안 패키지의 KeyStore 코드>를 구문 분석합니다. <code>java.security.KeyStore来解析。

微信支付Java에서의 WeChat 결제에 대한 자세한 설명(1): API V3 버전 서명使用了PKCS12算法,我们通过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);
        }
    }
}复制代码
로그인 후 복사

眼熟的可以看出是胖哥Spring Security教程中JWT用的公私钥提取方法的修改版本,你可以对比下不同之处。

这个方法中有三个参数,这里必须要说明一下:

  • keyPath  Java에서의 WeChat 결제에 대한 자세한 설명(1): API V3 버전 서명apiclient_cert.p12classpath路径,一般我们会放在resources路径下,当然你可以修改获取证书输入流的方式。
  • keyAlias 证书的别名,这个微信的文档是没有的,胖哥通过加载证书时进行DEBUG获取到该值固定为Tenpay Certificate
  • keyPass  证书密码,这个默认就是商户号,在其它配置中也需要使用就是mchid,就是你用超级管理员登录微信商户平台在个人资料中的一串数字。

3. V3签名

微信支付V3版本的签名是我们在调用具体的微信支付的API时在HTTP请求头中携带特定的编码串供微信支付服务器进行验证请求来源,确保请求是真实可信的。

签名格式

签名串的具体格式,一共五行一行也不能少,每一行以换行符n结束。

HTTP请求方法\n
URL\n
请求时间戳\n
请求随机串\n
请求报文主体\n复制代码
로그인 후 복사
  • HTTP请求方法  你调用的微信支付API所要求的请求方法,比如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请求直接为空字符"" ;当请求方法为POSTPUT时,请使用真实发送JSON报文。图片上传API,请使用meta对应的JSON报文。

生成签名

然后我们使用商户私钥对按照上面格式的待签名串进行SHA256 with 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
 */@SneakyThrowsString 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

  • 商户Java에서의 WeChat 결제에 대한 자세한 설명(1): API V3 버전 서명序列号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

WeChat 결제 API 인증서는 PKCS12 알고리즘을 사용하여 KeyStore를 사용하여 공개 및 개인 키 쌍 KeyPair와 인증서 일련번호 serialNumber, 도구 클래스를 캡슐화했습니다.

rrreee

익숙해 보이면 Spring에서 JWT에서 사용하는 공개 키 및 개인 키 추출 방법을 수정한 버전임을 알 수 있습니다. 보안 튜토리얼의 차이점을 비교할 수 있습니다.

이 메소드에는 세 가지 매개변수가 있으며 여기서 설명해야 합니다.

3. V3 서명

WeChat Pay V3 버전의 서명은 특정 WeChat Pay API A를 호출할 때입니다. 특정 인코딩 문자열은 WeChat 결제 서버의 HTTP 요청 헤더에 전달되어 요청 소스를 확인하여 요청이 확실하고 신뢰할 수 있는지 확인합니다.

서명 형식서명 문자열의 특정 형식은 총 5줄 이상이며, 각 줄은 개행 문자 n으로 끝납니다.
rrreee
  • HTTP 요청 방법 호출하는 WeChat 결제 API에 필요한 요청 방법(예: 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 요청인 경우 바로 널 문자"" code>; 요청 방법이 POST 또는 PUT인 경우 실제로 전송되는 JSON 메시지를 사용하세요. 이미지 업로드 API의 경우 meta에 해당하는 JSON 메시지를 사용하세요.

서명 생성

그런 다음 판매자의 개인 키를 사용하여 서명할 문자열에 대해 RSA 서명으로 SHA256을 수행합니다. 위 형식으로 서명 결과에 대해 Base64 인코딩을 수행하여 서명 값을 얻습니다. 해당 핵심 Java 코드는 다음과 같습니다. 🎜rrreee

4. 서명 사용 🎜🎜서명이 생성된 후 일부 매개변수와 결합하여 토큰을 형성합니다. code>를 HTTP 요청에 해당하는 <code>에 배치합니다. code>Authorization 요청 헤더에 형식은 다음과 같습니다. 🎜rrreee🎜Token은 다음 5개 부분으로 구성됩니다. 🎜
  • 🎜요청을 시작한 판매자(직접 연결된 판매자, 서비스 판매자 또는 채널 제공자 포함) 판매자 번호 mchid🎜
  • 🎜Merchant API 인증서 일련 번호 serial_no, 사용된 인증서를 선언하는 데 사용됨🎜
  • 🎜임의의 문자열 요청 nonce_str🎜
  • 🎜타임스탬프 timestamp code>🎜
  • 🎜서명값 서명🎜
  • 🎜Token생성된 핵심코드 : 🎜rrreee🎜생성된 코드를 넣어주세요 위 형식에 따라 요청 헤더에 토큰을 삽입하면 서명 사용이 완료됩니다. 🎜🎜5. 요약🎜🎜이 글에서는 WeChat Pay V3 버전의 어려운 서명과 서명 사용에 대해 완벽하게 분석했으며, API 인증서 분석도 설명했습니다. 결제 개발 관련 특정 문제. 🎜🎜🎜관련 무료 학습 추천: 🎜Basic Java Tutorial🎜🎜🎜관련 기사 소개: 🎜미니 프로그램 결제 기능 구현 방법🎜🎜🎜🎜

    위 내용은 Java에서의 WeChat 결제에 대한 자세한 설명(1): API V3 버전 서명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

    관련 라벨:
    원천:juejin.im
    본 웹사이트의 성명
    본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
    인기 튜토리얼
    더>
    최신 다운로드
    더>
    웹 효과
    웹사이트 소스 코드
    웹사이트 자료
    프론트엔드 템플릿