日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
創(chuàng)新互聯(lián)百度小程序教程:簽名與驗(yàn)簽
  • 簽名與驗(yàn)簽
    • 基本限定
    • 簽名規(guī)則
  • 簽名計(jì)算過(guò)程示例
  • 簽名工具參考代碼
  • 驗(yàn)證
    • 加簽邏輯驗(yàn)證
    • 驗(yàn)簽邏輯驗(yàn)證

    簽名與驗(yàn)簽

    本章節(jié)主要介紹百度收銀臺(tái)使用的雙向RSA加密簽名規(guī)則與相關(guān)示例。

    10年積累的網(wǎng)站建設(shè)、成都網(wǎng)站制作經(jīng)驗(yàn),可以快速應(yīng)對(duì)客戶對(duì)網(wǎng)站的新想法和需求。提供各種問(wèn)題對(duì)應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識(shí)你,你也不認(rèn)識(shí)我。但先建設(shè)網(wǎng)站后付款的網(wǎng)站建設(shè)流程,更有天涯免費(fèi)網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。

    基本限定

    1.統(tǒng)一字符集:UTF-8 ;
    百度收銀臺(tái)接口中的所有參數(shù)字符集均保持為 UTF-8 ,與收銀臺(tái)交互接入或者計(jì)算簽名時(shí),要統(tǒng)一使用 UTF-8 ,暫不支持其他字符集,請(qǐng)接入業(yè)務(wù)方自行轉(zhuǎn)換;
    2.請(qǐng)求接口的參數(shù)列表均為字符串類型鍵值對(duì);
    3.鍵值中如果為復(fù)雜數(shù)據(jù)類型,比如結(jié)構(gòu)體、數(shù)組、對(duì)象都必須先轉(zhuǎn)化為 JSON 結(jié)構(gòu)字符串;
    4.參數(shù)中包含漢字的部分,需要做 URLEncode 處理。

    簽名規(guī)則

    1.排除參數(shù)列表中名為 sign 和 sign_type 的參數(shù);
    2.將剩余參數(shù)按參數(shù)名字典序正序排列;
    3.將參數(shù)與其對(duì)應(yīng)的值使用 “=” 連接,組成參數(shù)字符串,將參數(shù)字符串按排序結(jié)果,使用 “&” 連接,組成待簽名字符串;
    4.將待簽名字符串和業(yè)務(wù)方私鑰使用 SHA1WithRSA 簽名算法得出最終簽名。

    簽名計(jì)算過(guò)程示例

    使用密鑰生成中的示例公私鑰來(lái)做計(jì)算演示。

    1.初始請(qǐng)求業(yè)務(wù)參數(shù)

    參數(shù)名 示例取值
    appKeyMMMabc
    dealId470193086
    tpOrderId3028903626
    totalAmount11300

    2.生成待簽名字符串

     
     
     
    1. appKey=MMMabc&dealId=470193086&totalAmount=11300&tpOrderId=3028903626

    3.生成最終簽名串

     
     
     
    1. TN0ZNPyQeTnPjCN5hUa7JwrXOhR8uDASXPazidVQHFSiGCH5aouBkVvJxtf8PeqzGYWAASwS2oOt2eJfunzC5dTFd/pWJeJToMgCSgRY7KtQUCCDnMrtpqiMAf+dLiXps3HpWhVB4CK6MXfHc64ejP5a2fu5bg8B0BTcHrqaGc0=

    4.簽名的完整請(qǐng)求參數(shù)

    參數(shù)名 示例取值
    appKeyMMMabc
    dealId470193086
    tpOrderId3028903626
    totalAmount11300
    rsaSignTN0ZNPyQeTnPjCN5hUa7JwrXOhR8uDASXPazidVQHFSiGCH5aouBkVvJxtf8PeqzGYWAASwS2oOt2eJfunzC5dTFd/pWJeJToMgCSgRY7KtQUCCDnMrtpqiMAf+dLiXps3HpWhVB4CK6MXfHc64ejP5a2fu5bg8B0BTcHrqaGc0=

    簽名工具參考代碼

    • PHP簽名工具類
     
     
     
    1. // 通用簽名工具,基于openssl擴(kuò)展,提供使用私鑰生成簽名和使用公鑰驗(yàn)證簽名的接口
    2. class RSASign
    3. {
    4. /**
    5. * @desc 使用私鑰生成簽名字符串
    6. * @param array $assocArr 入?yún)?shù)組
    7. * @param string $rsaPriKeyStr 私鑰原始字符串,不含PEM格式前后綴
    8. * @return string 簽名結(jié)果字符串
    9. * @throws Exception
    10. */
    11. public static function sign(array $assocArr, $rsaPriKeyStr)
    12. {
    13. $sign = '';
    14. if (empty($rsaPriKeyStr) || empty($assocArr)) {
    15. return $sign;
    16. }
    17. if (!function_exists('openssl_pkey_get_private') || !function_exists('openssl_sign')) {
    18. throw new Exception("openssl擴(kuò)展不存在");
    19. }
    20. $rsaPriKeyPem = self::convertRSAKeyStr2Pem($rsaPriKeyStr, 1);
    21. $priKey = openssl_pkey_get_private($rsaPriKeyPem);
    22. if (isset($assocArr['sign'])) {
    23. unset($assocArr['sign']);
    24. }
    25. // 參數(shù)按字典順序排序
    26. ksort($assocArr);
    27. $parts = array();
    28. foreach ($assocArr as $k => $v) {
    29. $parts[] = $k . '=' . $v;
    30. }
    31. $str = implode('&', $parts);
    32. openssl_sign($str, $sign, $priKey);
    33. openssl_free_key($priKey);
    34. return base64_encode($sign);
    35. }
    36. /**
    37. * @desc 使用公鑰校驗(yàn)簽名
    38. * @param array $assocArr 入?yún)?shù)據(jù),簽名屬性名固定為rsaSign
    39. * @param string $rsaPubKeyStr 公鑰原始字符串,不含PEM格式前后綴
    40. * @return bool true 驗(yàn)簽通過(guò)|false 驗(yàn)簽不通過(guò)
    41. * @throws Exception
    42. */
    43. public static function checkSign(array $assocArr, $rsaPubKeyStr)
    44. {
    45. if (!isset($assocArr['rsaSign']) || empty($assocArr) || empty($rsaPubKeyStr)) {
    46. return false;
    47. }
    48. if (!function_exists('openssl_pkey_get_public') || !function_exists('openssl_verify')) {
    49. throw new Exception("openssl擴(kuò)展不存在");
    50. }
    51. $sign = $assocArr['rsaSign'];
    52. unset($assocArr['rsaSign']);
    53. if (empty($assocArr)) {
    54. return false;
    55. }
    56. // 參數(shù)按字典順序排序
    57. ksort($assocArr);
    58. $parts = array();
    59. foreach ($assocArr as $k => $v) {
    60. $parts[] = $k . '=' . $v;
    61. }
    62. $str = implode('&', $parts);
    63. $sign = base64_decode($sign);
    64. $rsaPubKeyPem = self::convertRSAKeyStr2Pem($rsaPubKeyStr);
    65. $pubKey = openssl_pkey_get_public($rsaPubKeyPem);
    66. $result = (bool)openssl_verify($str, $sign, $pubKey);
    67. openssl_free_key($pubKey);
    68. return $result;
    69. }
    70. /**
    71. * @desc 將密鑰由字符串(不換行)轉(zhuǎn)為PEM格式
    72. * @param string $rsaKeyStr 原始密鑰字符串
    73. * @param int $keyType 0 公鑰|1 私鑰,默認(rèn)0
    74. * @return string PEM格式密鑰
    75. * @throws Exception
    76. */
    77. public static function convertRSAKeyStr2Pem($rsaKeyStr, $keyType = 0)
    78. {
    79. $pemWidth = 64;
    80. $rsaKeyPem = '';
    81. $begin = '-----BEGIN ';
    82. $end = '-----END ';
    83. $key = ' KEY-----';
    84. $type = $keyType ? 'PRIVATE' : 'PUBLIC';
    85. $keyPrefix = $begin . $type . $key;
    86. $keySuffix = $end . $type . $key;
    87. $rsaKeyPem .= $keyPrefix . "\n";
    88. $rsaKeyPem .= wordwrap($rsaKeyStr, $pemWidth, "\n", true) . "\n";
    89. $rsaKeyPem .= $keySuffix;
    90. if (!function_exists('openssl_pkey_get_public') || !function_exists('openssl_pkey_get_private')) {
    91. return false;
    92. }
    93. if ($keyType == 0 && false == openssl_pkey_get_public($rsaKeyPem)) {
    94. return false;
    95. }
    96. if ($keyType == 1 && false == openssl_pkey_get_private($rsaKeyPem)) {
    97. return false;
    98. }
    99. return $rsaKeyPem;
    100. }
    101. }
    • Java簽名工具類
     
     
     
    1. /*
    2. * Copyright (C) 2020 Baidu, Inc. All Rights Reserved.
    3. */
    4. package com.baidu.*;
    5. import static org.springframework.util.Assert.isTrue;
    6. import static org.springframework.util.Assert.notNull;
    7. import java.io.UnsupportedEncodingException;
    8. import java.net.URLEncoder;
    9. import java.security.KeyFactory;
    10. import java.security.NoSuchAlgorithmException;
    11. import java.security.PrivateKey;
    12. import java.security.PublicKey;
    13. import java.security.Signature;
    14. import java.security.spec.InvalidKeySpecException;
    15. import java.security.spec.PKCS8EncodedKeySpec;
    16. import java.security.spec.X509EncodedKeySpec;
    17. import java.util.Base64;
    18. import java.util.Comparator;
    19. import java.util.Map;
    20. import java.util.TreeMap;
    21. import org.springframework.util.CollectionUtils;
    22. import org.springframework.util.StringUtils;
    23. // 百度收銀臺(tái)雙向RSA簽名工具,JDK版本要求:1.8+
    24. public class RSASign {
    25. private static final String CHARSET = "UTF-8";
    26. private static final String SIGN_TYPE_RSA = "RSA";
    27. private static final String SIGN_ALGORITHMS = "SHA1WithRSA";
    28. private static final String SIGN_KEY = "rsaSign";
    29. /**
    30. * 使用私鑰生成簽名字符串
    31. *
    32. * @param params 待簽名參數(shù)集合
    33. * @param privateKey 私鑰原始字符串
    34. *
    35. * @return 簽名結(jié)果字符串
    36. *
    37. * @throws Exception
    38. */
    39. public static String sign(Map params, String privateKey) throws Exception {
    40. isTrue(!CollectionUtils.isEmpty(params), "params is required");
    41. notNull(privateKey, "privateKey is required");
    42. String signContent = signContent(params);
    43. Signature signature = Signature.getInstance(SIGN_ALGORITHMS);
    44. signature.initSign(getPrivateKeyPKCS8(privateKey));
    45. signature.update(signContent.getBytes(CHARSET));
    46. byte[] signed = signature.sign();
    47. return new String(Base64.getEncoder().encode(signed));
    48. }
    49. /**
    50. * 使用公鑰校驗(yàn)簽名
    51. *
    52. * @param params 入?yún)?shù)據(jù),簽名屬性名固定為rsaSign
    53. * @param publicKey 公鑰原始字符串
    54. *
    55. * @return true 驗(yàn)簽通過(guò) | false 驗(yàn)簽不通過(guò)
    56. *
    57. * @throws Exception
    58. */
    59. public static boolean checkSign(Map params, String publicKey) throws Exception {
    60. isTrue(!CollectionUtils.isEmpty(params), "params is required");
    61. notNull(publicKey, "publicKey is required");
    62. // sign & content
    63. String content = signContent(params);
    64. String rsaSign = params.get(SIGN_KEY).toString();
    65. // verify
    66. Signature signature = Signature.getInstance(SIGN_ALGORITHMS);
    67. signature.initVerify(getPublicKeyX509(publicKey));
    68. signature.update(content.getBytes(CHARSET));
    69. return signature.verify(Base64.getDecoder().decode(rsaSign.getBytes(CHARSET)));
    70. }
    71. /**
    72. * 對(duì)輸入?yún)?shù)進(jìn)行key過(guò)濾排序和字符串拼接
    73. *
    74. * @param params 待簽名參數(shù)集合
    75. *
    76. * @return 待簽名內(nèi)容
    77. *
    78. * @throws UnsupportedEncodingException
    79. */
    80. private static String signContent(Map params) throws UnsupportedEncodingException {
    81. Map sortedParams = new TreeMap<>(Comparator.naturalOrder());
    82. for (Map.Entry entry : params.entrySet()) {
    83. String key = entry.getKey();
    84. if (legalKey(key)) {
    85. String value =
    86. entry.getValue() == null ? null : URLEncoder.encode(entry.getValue().toString(), CHARSET);
    87. sortedParams.put(key, value);
    88. }
    89. }
    90. StringBuilder builder = new StringBuilder();
    91. if (!CollectionUtils.isEmpty(sortedParams)) {
    92. for (Map.Entry entry : sortedParams.entrySet()) {
    93. builder.append(entry.getKey());
    94. builder.append("=");
    95. builder.append(entry.getValue());
    96. builder.append("&");
    97. }
    98. builder.deleteCharAt(builder.length() - 1);
    99. }
    100. return builder.toString();
    101. }
    102. /**
    103. * 將公鑰字符串進(jìn)行Base64 decode之后,生成X509標(biāo)準(zhǔn)公鑰
    104. *
    105. * @param publicKey 公鑰原始字符串
    106. *
    107. * @return X509標(biāo)準(zhǔn)公鑰
    108. *
    109. * @throws InvalidKeySpecException
    110. * @throws NoSuchAlgorithmException
    111. */
    112. private static PublicKey getPublicKeyX509(String publicKey) throws InvalidKeySpecException,
    113. NoSuchAlgorithmException, UnsupportedEncodingException {
    114. if (StringUtils.isEmpty(publicKey)) {
    115. return null;
    116. }
    117. KeyFactory keyFactory = KeyFactory.getInstance(SIGN_TYPE_RSA);
    118. byte[] decodedKey = Base64.getDecoder().decode(publicKey.getBytes(CHARSET));
    119. return keyFactory.generatePublic(new X509EncodedKeySpec(decodedKey));
    120. }
    121. /**
    122. * 將私鑰字符串進(jìn)行Base64 decode之后,生成PKCS #8標(biāo)準(zhǔn)的私鑰
    123. *
    124. * @param privateKey 私鑰原始字符串
    125. *
    126. * @return PKCS #8標(biāo)準(zhǔn)的私鑰
    127. *
    128. * @throws Exception
    129. */
    130. private static PrivateKey getPrivateKeyPKCS8(String privateKey) throws Exception {
    131. if (StringUtils.isEmpty(privateKey)) {
    132. return null;
    133. }
    134. KeyFactory keyFactory = KeyFactory.getInstance(SIGN_TYPE_RSA);
    135. byte[] decodedKey = Base64.getDecoder().decode(privateKey.getBytes(CHARSET));
    136. return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(decodedKey));
    137. }
    138. /**
    139. * 有效的待簽名參數(shù)key值
    140. * 非空、且非簽名字段
    141. *
    142. * @param key 待簽名參數(shù)key值
    143. *
    144. * @return true | false
    145. */
    146. private static boolean legalKey(String key) {
    147. return StringUtils.hasText(key) && !SIGN_KEY.equalsIgnoreCase(key);
    148. }
    149. }

    驗(yàn)證

    加簽邏輯驗(yàn)證

    開發(fā)者實(shí)現(xiàn)加簽邏輯之后,使用計(jì)算示例中步驟 1 的初始請(qǐng)求參數(shù)作為輸入,結(jié)合密鑰生成中的示例私鑰,進(jìn)行 RSA 簽名的生成,如果結(jié)果與步驟 3 中最終簽名串一致,說(shuō)明加簽邏輯正確。

    驗(yàn)簽邏輯驗(yàn)證

    使用計(jì)算示例中步驟 4 完整請(qǐng)求參數(shù)作為輸入,結(jié)合密鑰生成中的示例公鑰,進(jìn)行 RSA 簽名的 check ,返回 true 則說(shuō)明驗(yàn)簽邏輯正確。


    當(dāng)前標(biāo)題:創(chuàng)新互聯(lián)百度小程序教程:簽名與驗(yàn)簽
    URL鏈接:http://www.dlmjj.cn/article/djhcphe.html