视频一区二区三区自拍_千金肉奴隷1985未删减版在线观看_国产成人黄色视频在线播放_少女免费播放片高清在线观看_国产精品v欧美精品v


簽名生成

商戶可以按照下述步驟生成請求的簽名。在本節(jié)的最后,我們準(zhǔn)備了多種常用編程語言的演示代碼供開發(fā)者參考。


微信支付API v3 要求商戶對請求進(jìn)行簽名。微信支付會(huì)在收到請求后進(jìn)行簽名的驗(yàn)證。如果簽名驗(yàn)證不通過,微信支付API v3將會(huì)拒絕處理請求,并返回401 Unauthorized

準(zhǔn)備

商戶需要擁有一個(gè)微信支付商戶號,并通過超級管理員賬號登錄商戶平臺,獲取商戶API證書。 商戶API證書的壓縮包中包含了簽名必需的私鑰和商戶證書。

構(gòu)造簽名串

我們希望商戶的技術(shù)開發(fā)人員按照當(dāng)前文檔約定的規(guī)則構(gòu)造簽名串。微信支付會(huì)使用同樣的方式構(gòu)造簽名串。如果商戶構(gòu)造簽名串的方式錯(cuò)誤,將導(dǎo)致簽名驗(yàn)證不通過。下面先說明簽名串的具體格式。

簽名串一共有五行,每一行為一個(gè)參數(shù)。行尾以 \n(換行符,ASCII編碼值為0x0A)結(jié)束,包括最后一行。如果參數(shù)本身以\n結(jié)束,也需要附加一個(gè)\n


					  HTTP請求方法\n
					  URL\n
					  請求時(shí)間戳\n
					  請求隨機(jī)串\n
					  請求報(bào)文主體\n
                

我們通過在命令行中調(diào)用"獲取微信支付平臺證書"接口,一步一步向開發(fā)者介紹如何進(jìn)行請求簽名。按照接口文檔,獲取商戶平臺證書的URL為 https://api.mch.weixin.qq.com/v3/certificates請求方法為GET,沒有查詢參數(shù)。

第一步,獲取HTTP請求的方法(GET,POST,PUT)等

GET

第二步,獲取請求的絕對URL,并去除域名部分得到參與簽名的URL。如果請求中有查詢參數(shù),URL末尾應(yīng)附加有'?'和對應(yīng)的查詢字符串。

/v3/certificates

第三步,獲取發(fā)起請求時(shí)的系統(tǒng)當(dāng)前時(shí)間戳,即格林威治時(shí)間1970年01月01日00時(shí)00分00秒(北京時(shí)間1970年01月01日08時(shí)00分00秒)起至現(xiàn)在的總秒數(shù),作為請求時(shí)間戳。微信支付會(huì)拒絕處理很久之前發(fā)起的請求,請商戶保持自身系統(tǒng)的時(shí)間準(zhǔn)確。

$ date +%s
1554208460

第四步,生成一個(gè)請求隨機(jī)串,可參見生成隨機(jī)數(shù)算法。這里,我們使用命令行直接生成一個(gè)。

$ hexdump -n 16 -e '4/4 "%08X" 1 "\n"' /dev/random
593BEC0C930BF1AFEB40B4A08C8FB242

第五步,獲取請求中的請求報(bào)文主體(request body)。

  • 請求方法為GET時(shí),報(bào)文主體為空。
  • 當(dāng)請求方法為POST或PUT時(shí),請使用真實(shí)發(fā)送的JSON報(bào)文。
  • 圖片上傳API,請使用meta對應(yīng)的JSON報(bào)文。

對于下載證書的接口來說,請求報(bào)文主體是一個(gè)空串。

第六步,按照前述規(guī)則,構(gòu)造的請求簽名串為:

 GET\n 
/v3/certificates\n
1554208460\n
593BEC0C930BF1AFEB40B4A08C8FB242\n
\n

計(jì)算簽名值

絕大多數(shù)編程語言提供的簽名函數(shù)支持對簽名數(shù)據(jù)進(jìn)行簽名。強(qiáng)烈建議商戶調(diào)用該類函數(shù),使用商戶私鑰對待簽名串進(jìn)行SHA256 with RSA簽名,并對簽名結(jié)果進(jìn)行Base64編碼得到簽名值。


 $ echo -n -e \
 "GET\n/v3/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==
                

設(shè)置HTTP頭

微信支付商戶API v3要求請求通過HTTP Authorization頭來傳遞簽名。 Authorization認(rèn)證類型簽名信息兩個(gè)部分組成。

下面我們使用命令行演示如何生成簽名。

Authorization: 認(rèn)證類型 簽名信息

具體組成為:

1.認(rèn)證類型,目前為WECHATPAY2-SHA256-RSA2048

2.簽名信息

  • 發(fā)起請求的商戶(包括直連商戶、服務(wù)商或渠道商)的商戶號 mchid
  • 商戶API證書序列號serial_no,用于聲明所使用的證書
  • 請求隨機(jī)串nonce_str
  • 時(shí)間戳timestamp
  • 簽名值signature
  • 注:以上五項(xiàng)簽名信息,無順序要求。

Authorization 頭的示例如下:(注意,示例因?yàn)榕虐婵赡艽嬖趽Q行,實(shí)際數(shù)據(jù)應(yīng)在一行)

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"

最終我們可以組一個(gè)包含了簽名的HTTP請求了。

$ curl https://api.mch.weixin.qq.com/v3/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"'
                  

演示代碼

開發(fā)者可以查看開發(fā)工具 相關(guān)章節(jié),獲取對應(yīng)語言的庫。如何在程序中加載私鑰,請參考常見問題

計(jì)算簽名的示例代碼如下。

import okhttp3.HttpUrl;
import java.security.Signature;
import java.util.Base64;

// Authorization: <schema> <token>
// GET - getToken("GET", httpurl, "")
// POST - getToken("POST", httpurl, json)
String schema = "WECHATPAY2-SHA256-RSA2048";
HttpUrl httpurl = HttpUrl.parse(url);

String getToken(String method, HttpUrl url, String body) {
    String nonceStr = "your nonce string";
    long timestamp = System.currentTimeMillis() / 1000;
    String message = buildMessage(method, url, timestamp, nonceStr, body);
    String signature = sign(message.getBytes("utf-8"));

    return "mchid=\"" + yourMerchantId + "\","
    + "nonce_str=\"" + nonceStr + "\","
    + "timestamp=\"" + timestamp + "\","
    + "serial_no=\"" + yourCertificateSerialNo + "\","
    + "signature=\"" + signature + "\"";
}

String sign(byte[] message) {
    Signature sign = Signature.getInstance("SHA256withRSA");
    sign.initSign(yourPrivateKey);
    sign.update(message);

    return Base64.getEncoder().encodeToString(sign.sign());
}

String buildMessage(String method, HttpUrl url, long timestamp, String nonceStr, String body) {
    String canonicalUrl = url.encodedPath();
    if (url.encodedQuery() != null) {
      canonicalUrl += "?" + url.encodedQuery();
    }

    return method + "\n"
        + canonicalUrl + "\n"
        + timestamp + "\n"
        + nonceStr + "\n"
        + body + "\n";
}
                
// Authorization: <schema> <token>
$url_parts = parse_url($url);
$canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));
$message = $http_method."\n".
$canonical_url."\n".
$timestamp."\n".
$nonce."\n".
$body."\n";
                    
openssl_sign($message, $raw_sign, $mch_private_key, 'sha256WithRSAEncryption');
$sign = base64_encode($raw_sign);
                    
$schema = 'WECHATPAY2-SHA256-RSA2048';
$token = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
$merchant_id, $nonce, $timestamp, $serial_no, $sign);
                  

using System;
using System.IO;
using System.Net.Http;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;

namespace HttpHandlerDemo
{
    // 使用方法
    // HttpClient client = new HttpClient(new HttpHandler("{商戶號}", "{商戶證書序列號}"));
    // ...
    // var response = client.GetAsync("https://api.mch.weixin.qq.com/v3/certificates");
    public class HttpHandler : DelegatingHandler
    {
        private readonly string merchantId;
        private readonly string serialNo;

        public HttpHandler(string merchantId, string merchantSerialNo)
        {
            InnerHandler = new HttpClientHandler();

            this.merchantId = merchantId;
            this.serialNo = merchantSerialNo;
        }

        protected async override Task<HttpResponseMessage> SendAsync(
            HttpRequestMessage request,
            CancellationToken cancellationToken)
        {
            var auth = await BuildAuthAsync(request);
            string value = $"WECHATPAY2-SHA256-RSA2048 {auth}";
            request.Headers.Add("Authorization", value);

            return await base.SendAsync(request, cancellationToken);
        }

        protected async Task<string> BuildAuthAsync(HttpRequestMessage request)
        {
            string method = request.Method.ToString();
            string body = "";
            if (method == "POST" || method == "PUT" || method == "PATCH")
            {
                var content = request.Content;
                body = await content.ReadAsStringAsync();
            }

            string uri = request.RequestUri.PathAndQuery;
            var timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
            string nonce = Path.GetRandomFileName();

            string message = $"{method}\n{uri}\n{timestamp}\n{nonce}\n{body}\n";
            string signature = Sign(message);
            return $"mchid=\"{merchantId}\",nonce_str=\"{nonce}\",timestamp=\"{timestamp}\",serial_no=\"{serialNo}\",signature=\"{signature}\"";
        }

        protected string Sign(string message)
        {
            // NOTE: 私鑰不包括私鑰文件起始的-----BEGIN PRIVATE KEY-----
            //        亦不包括結(jié)尾的-----END PRIVATE KEY-----
            string privateKey = "{你的私鑰}";
            byte[] keyData = Convert.FromBase64String(privateKey);
            
            var rsa = RSA.Create();
            //適用該方法的版本https://learn.microsoft.com/zh-cn/dotnet/api/system.security.cryptography.asymmetricalgorithm.importpkcs8privatekey?view=net-7.0
rsa.ImportPkcs8PrivateKey(keyData, out _);
            rsa.ImportPkcs8PrivateKey(keyData, out _);
            byte[] data = System.Text.Encoding.UTF8.GetBytes(message);
            return Convert.ToBase64String(rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
        }
    }
}
                  
如果您的請求返回了簽名錯(cuò)誤401 Unauthorized,請參考 常見問題之簽名相關(guān)


技術(shù)咨詢

文檔反饋