Signature Generation
Merchants can follow the steps below to generate the requested signature. At the end of this section, we have prepared demo codes in a variety of commonly used programming languages for developers' reference.。
Merchants can follow the steps below to generate the requested signature. At the end of this section, we have prepared demo codes in a variety of commonly used programming languages for developers' reference.。
WeChat Pay API V3 requires merchants to sign the request. WeChat Pay will verify the signature after receiving the request. If signature verification fails, WeChat Pay API V3 will refuse to process the request and return 401 Unauthorized
.
A merchant needs to obtain a WeChat Pay merchant account, log in to the merchant platform through the super administrator account, and obtain the Merchant API Certificate . The compressed package of Merchant API Certificate contains the private key and merchant certificate necessary for signing.
Constructing a Signature String We hope that the merchant's technical developers will construct the signature string according to the conventions specified in the current document. WeChat Pay uses the same method to construct the signature string. The signature will not be verified if the merchant constructs the signature string incorrectly. The specific format of the signature string is explained below.
A signature string has five lines, and each line has a parameter. Each line ends with \n
(Newline character; the ASCII code value is 0x0A), and even the last line shall end with \n. If the parameter itself ends with \n
, an additional \n
is also required.
HTTP request method\n
URL\ n
Request timestamp\n
Request random string\n
Request body\n
By calling the Obtaining WeChat Pay Platform Certificate API in the command line, we will provide developers with step by step instructions on how to request signatures. According to the API document, the URL for obtaining the merchant platform certificate is https://apihk.mch.weixin.qq.com/v3/global/certificates
. The request method is GET
with no query parameters.
Step 1: Obtain the HTTP request method (such as GET, POST, and PUT).
GET
Step 2: Obtain the absolute URL of the request, and remove the domain to obtain the URL participating in the signature. If the request has query parameters, a '?' and the corresponding query string should be added to the end of the URL.
/v3/global/certificates
Step 3: Obtain the current timestamp of the system when the request was initiated. Timestamps include the total number of seconds from January 1, 1970, 00: 00: 00, GMT (Beijing time, January 1, 1970, 08: 00: 00) to the present time. WeChat Pay will refuse to process requests initiated a long time ago. Merchants are requested to keep their system time accurate.
$ date +%s
1554208460
Step 4: Generate a random string request, referring to Algorithm for Generating Random Numbers.Here, we use the command line to directly generate a random string request.
$ hexdump -n 16 -e '4/4 "%08X" 1 "\n"' /dev/random
593BEC0C930BF1AFEB40B4A08C8FB242
Step 5: Obtain the request body in the request.
• When the request method is GET, the message body is blank.
• When the request method is POST or PUT, use the actual JSON message sent.
• For an image upload API, use the JSON message corresponding to meta.
For a certificate download API, the request body is an empty string.
Step 6: According to the aforementioned rules, the constructed request signature string is:
GET\n
/v3/global/certificates\n
1554208460\n
593BEC0C930BF1AFEB40B4A08C8FB242\n
\n
The signature functions provided by most programming languages support signing signature data. It is recommended that merchants call such functions, use the merchant's private key to sign the signature string with SHA256 with RSA, and perform Base64 encoding on the signature result to obtain the signature value.
$ echo -n -e \
"GET\n/v3/global/certificates\n1554208460\n593BEC0C930BF1AFEB40B4A08C8FB242\n\n" \
| openssl dgst -sha256 -sign apiclient_key.pem \
| openssl base64 -A
uOVRnA4qG/MNnYzdQxJanN+zU+lTgIcnU9BxGw5dKjK+VdEUz2FeIoC+D5sB/LN+nGzX3hfZg6r5wT1pl2ZobmIc6p0ldN7J6yDgUzbX8Uk3sD4a4eZVPTBvqNDoUqcYMlZ9uuDdCvNv4TM3c1WzsXUrExwVkI1XO5jCNbgDJ25nkT/c1gIFvqoogl7MdSFGc4W4xZsqCItnqbypR3RuGIlR9h9vlRsy7zJR9PBI83X8alLDIfR1ukt1P7tMnmogZ0cuDY8cZsd8ZlCgLadmvej58SLsIkVxFJ8XyUgx9FmutKSYTmYtWBZ0+tNvfGmbXU7cob8H/4nLBiCwIUFluw==
WeChat Pay Merchant API V3 requires the request to pass the signature through the HTTP Authorization
header. Authorization
is composed of the authentication type and signature information.
Here we use command lines to demonstrate how to generate a signature.
Authorization: authentication type and signature information
Authorization includes:
1.Authentication type, currently WECHATPAY2-SHA256-RSA2048
2.Signature information
• This is the merchant ID mchid
of the merchant that initiated the request (including directly connected merchants, service providers, or channel merchants)
• The Merchant API Certificate serial number, serial_no
, is used for Declaring the Certificate Used
• Request random string nonce_str
• Timestamp timestamp
• Signature value signature
An example of the Authorization
header is as follows: (note that the example may have line breaks due to typesetting. The actual data should be on one line.)
Authorization: WECHATPAY2-SHA256-RSA2048 mchid="1900009191",nonce_str="593BEC0C930BF1AFEB40B4A08C8FB242",signature="uOVRnA4qG/MNnYzdQxJanN+zU+lTgIcnU9BxGw5dKjK+VdEUz2FeIoC+D5sB/LN+nGzX3hfZg6r5wT1pl2ZobmIc6p0ldN7J6yDgUzbX8Uk3sD4a4eZVPTBvqNDoUqcYMlZ9uuDdCvNv4TM3c1WzsXUrExwVkI1XO5jCNbgDJ25nkT/c1gIFvqoogl7MdSFGc4W4xZsqCItnqbypR3RuGIlR9h9vlRsy7zJR9PBI83X8alLDIfR1ukt1P7tMnmogZ0cuDY8cZsd8ZlCgLadmvej58SLsIkVxFJ8XyUgx9FmutKSYTmYtWBZ0+tNvfGmbXU7cob8H/4nLBiCwIUFluw==",timestamp="1554208460",serial_no="1DDE55AD98ED71D6EDD4A4A16996DE7B47773A8C"
Finally, we can create an HTTP request that includes a signature.
$ curl https://apihk.mch.weixin.qq.com/v3/global/certificates -H 'Authorization: WECHATPAY2-SHA256-RSA2048 mchid="1900009191",nonce_str="593BEC0C930BF1AFEB40B4A08C8FB242",signature="uOVRnA4qG/MNnYzdQxJanN+zU+lTgIcnU9BxGw5dKjK+VdEUz2FeIoC+D5sB/LN+nGzX3hfZg6r5wT1pl2ZobmIc6p0ldN7J6yDgUzbX8Uk3sD4a4eZVPTBvqNDoUqcYMlZ9uuDdCvNv4TM3c1WzsXUrExwVkI1XO5jCNbgDJ25nkT/c1gIFvqoogl7MdSFGc4W4xZsqCItnqbypR3RuGIlR9h9vlRsy7zJR9PBI83X8alLDIfR1ukt1P7tMnmogZ0cuDY8cZsd8ZlCgLadmvej58SLsIkVxFJ8XyUgx9FmutKSYTmYtWBZ0+tNvfGmbXU7cob8H/4nLBiCwIUFluw==",timestamp="1554208460",serial_no="1DDE55AD98ED71D6EDD4A4A16996DE7B47773A8C"'
Developers can visit Development Tool to obtain the corresponding language library.Please refer to FAQs on how to load the private key in the program.
The sample code for calculating the signature is as follows.
import okhttp3.HttpUrl;
package com.wechat.v3;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpRequestBase;
import org.junit.Test;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.Base64;
public class SignTest {
protected static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
protected static final SecureRandom RANDOM = new SecureRandom();
protected static final PrivateKey privateKey = null; //need to be initialized
protected static final String certificateSerialNumber = null; //need to be initialized
protected static final String merchantId = null; //need to be initialized
@Test
public void signTest() throws IOException {
HttpGet httpGet = new HttpGet("https://apihk.mch.weixin.qq.com/v3/global/certificates");
httpGet.addHeader("Accept", "application/json");
httpGet.addHeader("Content-type", "application/json; charset=utf-8");
System.out.println(getToken(httpGet,""));
}
public String getToken(HttpRequestBase request, String body) throws IOException {
String nonceStr = generateNonceStr();
long timestamp = generateTimestamp();
String message = buildMessage(nonceStr, timestamp, request, body);
// log.debug("authorization message=[{}]", message);
String signature = sign(message.getBytes(StandardCharsets.UTF_8));
String token = "mchid=\"" + merchantId + "\","
+ "nonce_str=\"" + nonceStr + "\","
+ "timestamp=\"" + timestamp + "\","
+ "serial_no=\"" + certificateSerialNumber + "\","
+ "signature=\"" + signature + "\"";
// log.debug("authorization token=[{}]", token);
return token;
}
public String sign(byte[] message) {
try {
Signature sign = Signature.getInstance("SHA256withRSA");
sign.initSign(privateKey);
sign.update(message);
return Base64.getEncoder().encodeToString(sign.sign());
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("当前Java环境不支持SHA256withRSA", e);
} catch (SignatureException e) {
throw new RuntimeException("签名计算失败", e);
} catch (InvalidKeyException e) {
throw new RuntimeException("无效的私钥", e);
}
}
protected String buildMessage(String nonce, long timestamp, HttpRequestBase request, String body) throws IOException {
URI uri = request.getURI();
String canonicalUrl = uri.getRawPath();
if (uri.getQuery() != null) {
canonicalUrl += "?" + uri.getRawQuery();
}
return request.getRequestLine().getMethod() + "\n"
+ canonicalUrl + "\n"
+ timestamp + "\n"
+ nonce + "\n"
+ body + "\n";
}
protected long generateTimestamp() {
return System.currentTimeMillis() / 1000;
}
protected String generateNonceStr() {
char[] nonceChars = new char[32];
for (int index = 0; index < nonceChars.length; ++index) {
nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
}
return new String(nonceChars);
}
}
Customer Service Tel
Business Development
9:00-18:00
Monday-Friday GMT+8
Technical Support
WeChat Pay Global
ICP证