cshenfu
2023-06-14 de93aa62c83d6afb9f70cd5a22838375db0a8cbc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/**
 * 支付宝相关函数
 */
const common = require('./common');
const crypto = require('crypto');
 
const ALIPAY_ALGORITHM_MAPPING = {
    RSA: 'RSA-SHA1',
    RSA2: 'RSA-SHA256'
}
 
var alipay = {
    /**
     * 获取openid
     */
    async getOpenid(data) {
        let {
            config={},
            code,
        } = data;
        if (!config.appId) throw new Error("uni-pay配置alipay.mp节点下的appId不能为空");
        if (!config.privateKey) throw new Error("uni-pay配置alipay.mp节点下的privateKey不能为空");
        let timestamp = common.timeFormat(new Date(), "yyyy-MM-dd hh:mm:ss");
        let method = "alipay.system.oauth.token";
        let params = {
            timestamp,
            code,
            grant_type: "authorization_code"
        };
        let signData = this._getSign(method, params, config);
        // 格式化url和请求参数
        const { url, execParams } = this._formatUrl(signData);
        let res = await uniCloud.httpclient.request(url, {
            method: 'POST',
            data: execParams,
            dataType: 'text',
        });
        const result = JSON.parse(res.data)
        let response = result.alipay_system_oauth_token_response;
        if (res.status === 200 && response.user_id) {
            return {
                errCode: 0,
                errMsg: 'ok',
                openid: response.user_id,
                user_id: response.user_id,
            }
        } else {
            return {
                errCode: -1,
                errMsg: result.error_response.sub_msg
            }
        }
    },
 
    /**
     * 签名
     * @param {String} method 方法名
     * @param {Object} params 参数
     * @param {Object} config 配置
     */
    _getSign(method, params, config) {
        let signParams = Object.assign({
            method,
            app_id: config.appId,
            charset: config.charset || "utf-8",
            version: config.version || "1.0",
            sign_type: config.signType || "RSA2",
        }, params);
        if (config.appCertSn && config.alipayRootCertSn) {
            signParams = Object.assign({
                app_cert_sn: config.appCertSn,
                alipay_root_cert_sn: config.alipayRootCertSn,
            }, signParams);
        }
        const bizContent = params.biz_content;
        if (bizContent) {
            signParams.biz_content = JSON.stringify(bizContent);
        }
        // 排序
        const decamelizeParams = this._sortObj(signParams);
        // 拼接url参数
        let signStr = this._objectToUrl(decamelizeParams);
 
        let keyType = config.keyType || 'PKCS8';
        const privateKeyType = keyType === 'PKCS8' ? 'PRIVATE KEY' : 'RSA PRIVATE KEY'
        let privateKey = this._formatKey(config.privateKey, privateKeyType);
        // 计算签名
        const sign = crypto.createSign(ALIPAY_ALGORITHM_MAPPING[signParams.sign_type])
            .update(signStr, 'utf8').sign(privateKey, 'base64');
        return Object.assign(decamelizeParams, { sign });
    },
 
    _formatKey(key, type) {
        return `-----BEGIN ${type}-----\n${key}\n-----END ${type}-----`
    },
    _sortObj(params) {
        let keysArr = Object.keys(params).sort();
        let sortObj = {};
        for (let i in keysArr) {
            sortObj[keysArr[i]] = (params[keysArr[i]]);
        }
        return sortObj;
    },
    _objectToUrl(obj) {
        let str = "";
        for (let key in obj) {
            if (obj[key]) {
                str += `&${key}=${obj[key]}`;
            }
        }
        if (str) str = str.substring(1);
        return str;
    },
    _formatUrl(params, url = "https://openapi.alipay.com/gateway.do") {
        let requestUrl = url;
        // 需要放在 url 中的参数列表
        const urlArgs = [
            'app_id',
            'method',
            'format',
            'charset',
            'sign_type',
            'sign',
            'timestamp',
            'version',
            'notify_url',
            'return_url',
            'auth_token',
            'app_auth_token'
        ]
 
        for (const key in params) {
            if (urlArgs.indexOf(key) > -1) {
                const val = encodeURIComponent(params[key])
                requestUrl = `${requestUrl}${requestUrl.includes('?') ? '&' : '?'
              }${key}=${val}`
                // 删除 postData 中对应的数据
                delete params[key]
            }
        }
 
        return { execParams: params, url: requestUrl }
    }
};
module.exports = alipay;