diff --git a/README.md b/README.md index 3211915..1c7eb39 100644 --- a/README.md +++ b/README.md @@ -362,6 +362,34 @@ const success = sdk.checkNotifySignV2(postData); const plainText = alipaySdk.aesDecrypt(getPhoneNumberResponse); ``` +### 对前端返回的报文进行验签 + +参考 https://opendocs.alipay.com/common/02mse3#AES%20%E8%A7%A3%E5%AF%86%E5%87%BD%E6%95%B0 的算法 + +前端返回的内容 + +```json +{ + "response": "hvDOnibG0DPcOFPNubK3DEfLQGL4=", + "sign": "OIwk7zfZMp5GX78Ow==", + "sign_type": "RSA2", + "encrypt_type": "AES", + "charset": "UTF-8" +} +``` + +通过 alipay-sdk 验签 + +```ts +// 注意,加密内容必须前后加上双引号 +const signContent = '"hvDOnibG0DPcOFPNubK3DEfLQGL4="'; +const sign = 'OIwk7zfZMp5GX78Ow=='; +const signType = 'RSA2'; +const signCheckPass = alipaySdk.rsaCheck(signContent, sign, signType); + +console.log(signCheckPass); +``` + ## alipay-sdk v3 到 v4 的升级说明 从 v3 到 v4 有以下不兼容变更,请参考示例代码进行更新 diff --git a/src/alipay.ts b/src/alipay.ts index ffbf8cf..a2525ea 100644 --- a/src/alipay.ts +++ b/src/alipay.ts @@ -9,7 +9,7 @@ import camelcaseKeys from 'camelcase-keys'; import snakeCaseKeys from 'snakecase-keys'; import { Stream as SSEStream } from 'sse-decoder'; import { AlipayFormStream } from './AlipayFormStream.js'; -import type { AlipaySdkConfig } from './types.js'; +import type { AlipaySdkConfig, AlipaySdkSignType } from './types.js'; import { AlipayFormData } from './form.js'; import { sign, ALIPAY_ALGORITHM_MAPPING, decamelize, createRequestId, readableToBytes, @@ -732,7 +732,7 @@ export class AlipaySdk { } // 消息验签 - private notifyRSACheck(signArgs: { [key: string]: any }, signStr: string, signType: 'RSA' | 'RSA2', raw?: boolean) { + private notifyRSACheck(signArgs: { [key: string]: any }, signStr: string, signType: AlipaySdkSignType, raw?: boolean) { const signContent = Object.keys(signArgs).sort().filter(val => val) .map(key => { let value = signArgs[key]; @@ -748,10 +748,7 @@ export class AlipaySdk { return `${key}=${decodeURIComponent(value)}`; }) .join('&'); - - const verifier = createVerify(ALIPAY_ALGORITHM_MAPPING[signType]); - - return verifier.update(signContent, 'utf8').verify(this.config.alipayPublicKey, signStr, 'base64'); + return this.rsaCheck(signContent, signStr, signType); } /** @@ -1024,4 +1021,14 @@ export class AlipaySdk { aesDecrypt(encryptedText: string) { return aesDecryptText(encryptedText, this.config.encryptKey); } + + /** + * 对指定内容进行验签 + * + * 如对前端返回的报文进行验签 https://opendocs.alipay.com/common/02mse3#AES%20%E8%A7%A3%E5%AF%86%E5%87%BD%E6%95%B0 + */ + rsaCheck(signContent: string, sign: string, signType: AlipaySdkSignType = 'RSA2') { + const verifier = createVerify(ALIPAY_ALGORITHM_MAPPING[signType]); + return verifier.update(signContent, 'utf-8').verify(this.config.alipayPublicKey, sign, 'base64'); + } } diff --git a/src/types.ts b/src/types.ts index d93020c..d84df26 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,3 +1,5 @@ +export type AlipaySdkSignType = 'RSA2' | 'RSA'; + /** * @interface AlipaySdkConfig SDK 配置 */ @@ -7,7 +9,7 @@ export interface AlipaySdkConfig { /** 应用私钥字符串。RSA签名验签工具:https://docs.open.alipay.com/291/106097)*/ privateKey: string; /** 签名种类,默认是 RSA2 */ - signType?: 'RSA2' | 'RSA'; + signType?: AlipaySdkSignType; /** 支付宝公钥(需要对返回值做验签时候必填) */ alipayPublicKey?: string; /** 网关 */