uni-app小程序开发-支付宝小程序一键登录

前言

一键登录的思路是

获取支付宝账号的手机号,如果手机号已存在就自动登录,如果不存在就生成该手机号的账号信息,当然也可以让用户绑定自己的账号信息。

所以我们要先获取手机号:

https://opendocs.alipay.com/mini/api/getphonenumber?pathHash=a67c2790

image-20240520180829776

注意

获取会员手机号仅对企业支付宝账户开放,个人账号不支持,详见获取会员手机号

获取会员手机号仅对企业支付宝账户开放,个人账号不支持,详见获取会员手机号

获取会员手机号仅对企业支付宝账户开放,个人账号不支持,详见获取会员手机号

常用地址

开放平台

https://open.alipay.com/develop/manage

创建小程序

https://open.alipay.com/develop/mini/create?bundleId=com.alipay.alipaywallet&from=createMenuPage

小程序API

https://opendocs.alipay.com/mini/api/

获取手机号

https://opendocs.alipay.com/mini/api/getphonenumber

小程序获取手机号

页面中

1
2
3
4
<!-- #ifdef  MP-ALIPAY  -->
<button class="login" type="default" open-type="getAuthorize" @getAuthorize="onGetAuthorize"
@error="onAuthError" scope='phoneNumber'>授权手机号一键登录</button>
<!-- #endif -->

JS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
onGetAuthorize: function() {
return new Promise((resolve, reject) => {
my.getPhoneNumber({
scopes: "auth_user",
success: res => {
console.info("response", res.response);
this.zfbLogin(res.response); // 调取这个自定义方法
resolve(res);
},
fail: res => {
reject(res);
}
});
});
},

response 是一个JSON对象转的字符串,包含两个属性:

responsesign,我们可以前端取传给后端,也可以传整个字符串让后端解析。

服务端解密

添加引用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<dependencies>
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.39.74.ALL</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.70</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.50</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>

代码

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
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.parser.Feature;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipayEncrypt;
import com.alipay.api.internal.util.AlipaySignature;

import java.util.Map;

public class MyTest {
public static void main(String[] args) throws Exception {
String response = "{\"response\":\"xxxxxxx\",\"sign\":\"xxx\"}";

getResult(response);
}

public static String getResult(String response) throws Exception {
//1. 获取验签和解密所需要的参数
Map<String, String> openapiResult = JSON.parseObject(response, new TypeReference<Map<String, String>>() {
}, Feature.OrderedField);

String sign = openapiResult.get("sign");
String content = openapiResult.get("response");
//判断是否为加密内容
boolean isDataEncrypted = !content.startsWith("{");
boolean signCheckPass = false;
//2. 验签
String signType = "RSA2";
String charset = "UTF-8";
String encryptType = "AES";
String signContent = content;
String signVeriKey = "你的小程序对应的支付宝公钥(为扩展考虑建议用appId+signType做密钥存储隔离)";
String decryptKey = "你的小程序对应的加解密密钥(为扩展考虑建议用appId+encryptType做密钥存储隔离)";//如果是加密的报文则需要在密文的前后添加双引号
if (isDataEncrypted) {
signContent = "\"" + signContent + "\"";
}
try {
signCheckPass = AlipaySignature.rsaCheck(signContent, sign, signVeriKey, charset, signType);
} catch (AlipayApiException e) {
// 验签异常, 日志
}
if (!signCheckPass) {
//验签不通过(异常或者报文被篡改),终止流程(不需要做解密)
throw new Exception("验签失败");
}
//3. 解密
String plainData = null;
if (isDataEncrypted) {
try {
plainData = AlipayEncrypt.decryptContent(content, encryptType, decryptKey, charset);
} catch (AlipayApiException e) {
//解密异常, 记录日志
throw new Exception("解密异常");
}
} else {
plainData = content;
}

System.out.println("plainData:" + plainData);
return plainData;
}
}

获取用户信息

获取用户信息不用解密,用户信息仅包含用户的昵称和头像。

页面

1
<button open-type="getAuthorize" scope="userInfo" @getAuthorize="getOpenUserInfo"> 会员基础信息授权 </button>

JS

1
2
3
4
5
6
7
8
9
10
11
getOpenUserInfo: function() {
my.getOpenUserInfo({
success: (res) => {
let userInfo = JSON.parse(res.response).response;
console.info("userInfo", userInfo);
},
fail: (err) => {
console.log(err)
}
});
},