uniapp微信小程序授权登录并获取手机号的方法

网友投稿 420 2023-11-14

目录登录逻辑新版老版解密工具类api总结

新版:前端要授权两次,一次获取用户信息授权码code,另外一次获取用户手机授权码code,全部传给后端。后端通过用户信息授权码获取openid,通过手机授权码获取手机号码。老版:前端传给后端授权码code和用户手机授权回调 里的iv和encryptedData给后端,后端通过code获取openid和sessionKey,然后他用sessionKey和iv解密encryptedData获取手机号。最后通过手机号进行绑定用户,然后通过登录验证返回给前端登录凭证token。

登录逻辑

新版

uniapp微信小程序授权登录并获取手机号的方法

1.调用uni.login()获取code1

2.用户主动触发button按钮在回调getPhoneNumber获取code2

?
1
2
3
4
5
6
<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber"></button>
Page({
getPhoneNumber (e) {
console.log(e.detail.code)
}
})

3.后端拿到code1获取openid ,code2获取手机号码(代码在api里面)

老版

1.先在onshow()生命周期中获取code

2.用户主动触发button按钮在回调getPhoneNumber获取iv和encryptedData

3.后端拿到code、iv、encryptedData,然后code获取openid和sessionKey,然后通过sessionKey和iv解密encryptedData获取到手机号

?
1
2
3
4
5
6
7
8
9
10
11
获取得到的解密数据为以下 json 结构:
{
"phoneNumber": "13580006666",
"purePhoneNumber": "13580006666",
"countryCode": "86",
"watermark":
{
"appid":"APPID",
"timestamp": TIMESTAMP
}
}

解密工具类

?
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
package hry.project.cdwjs.wxLogin;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.*;
/**
* @author qyb
* @version 1.0
* @date 2023/3/13-9:38
*/
public class WxDecryptUtills {
public static boolean initialized = false;
/**
* Adds a provider to the next position available.
*/
public static void initialize() {
if (initialized) return;
// Construct a new provider.  This should only be required when
// using runtime registration of the provider using the
Security.addProvider(new BouncyCastleProvider());
initialized = true;
}
// iv处理
public static AlgorithmParameters generateIV(byte[] iv) throws Exception{
AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
params.init(new IvParameterSpec(iv));
return params;
}
/**
* AES解密
* @param content 密文
* @param keyByte sessionKey
* @param ivByte iv
* @return 解密json数据
*/
public static byte[] decrypt(byte[] content, byte[] keyByte, byte[] ivByte)  {
initialize();
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
Key sKeySpec = new SecretKeySpec(keyByte, "AES");
// cipher 初始化
cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(ivByte));
return cipher.doFinal(content);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 微信小程序用户信息解密
* @param encryptedData 加密数据
* @param sessionKey    会话密钥
* @param iv            向量
* @return {@link String}
*/
public static String decrypt(String encryptedData, String sessionKey, String iv){
try {
byte[] resultByte = decrypt(Base64.decodeBase64(encryptedData), Base64.decodeBase64(sessionKey), Base64.decodeBase64(iv));
if(null != resultByte && resultByte.length > 0){
return new String(resultByte, StandardCharsets.UTF_8);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}

api

?
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
package hry.project.cdwjs.wxLogin.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import hry.bean.JsonResult;
import hry.business.cu.model.CuCustomer;
import hry.business.cu.service.CuCustomerService;
import hry.project.cdwjs.wxLogin.WxDecryptUtills;
import hry.project.cdwjs.wxLogin.WxLoginService;
import hry.project.cdwjs.wxLogin.WxLoginVo;
import hry.redis.RedisService;
import hry.security.jwt.JWTToken;
import hry.security.jwt.JWTUtil;
import hry.utils.HttpUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.HashMap;
/**
* @author qyb
* @version 1.0
* @date 2023/3/9-17:38
*/
@Service
@Slf4j
public class WxLoginServiceImpl implements WxLoginService {
@Value("${wxLogin.appId}")
private String appId;
@Value("${wxLogin.appSecret}")
private String appSecret;
@Autowired
private CuCustomerService cuCustomerService;
@Autowired
private RedisService redisService;
/**
* 获取accesstoken
*
* @return
*/
private String getAccessToken() {
String accessToken = "";
String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret=" + appSecret;
try {
String resultString = HttpUtils.get(url);
log.info("获取微信accessToken:{}", resultString);
if (StringUtils.isNotEmpty(resultString)) {
JSONObject jsonObject = JSON.parseObject(resultString);
accessToken = jsonObject.get("access_token").toString();
} else {
log.error("返回值为空,请检查请求报文或者请求地址是否正确");
}
} catch (Exception e) {
e.printStackTrace();
}
return accessToken;
}
/**
* 获取手机号
*/
private String getPhoneNumber(String code) {
String phoneNumber = "";
String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + getAccessToken();
HashMap<String, String> params = new HashMap<>();
params.put("code", code);
try {
String resultString = HttpUtils.postByQuery(url, params, null);
log.info("获取微信手机号码:{}", resultString);
if (StringUtils.isNotEmpty(resultString)) {
JSONObject jsonObject = JSON.parseObject(resultString);
JSONObject phone_info = jsonObject.getJSONObject("phone_info");
phoneNumber = phone_info.getString("phoneNumber");
} else {
log.error("返回值为空,请检查请求报文或者请求地址是否正确");
}
} catch (Exception e) {
e.printStackTrace();
}
return phoneNumber;
}
/**
* 获取openId
*/
private String getOpenId(String code) {
String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + appId + "&secret=" + appSecret + "&js_code=" + code + "&grant_type=authorization_code";
try {
String resultString = HttpUtils.get(url);
log.info("获取微信openId:{}", resultString);
if (StringUtils.isNotEmpty(resultString)) {
return resultString;
} else {
log.error("返回值为空,请检查请求报文或者请求地址是否正确");
}
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
@Override
public JsonResult loginByWx(WxLoginVo wxLoginVo) {
String res = this.getOpenId(wxLoginVo.getUserInfoCode());
JSONObject jsonObject = JSONObject.parseObject(res);
String openId = jsonObject.getString("openid");
String sessionKey = jsonObject.getString("session_key");
if (StringUtils.isEmpty(openId)) {
return new JsonResult().setMsg("未获取到openId,登录失败");
}
String data = WxDecryptUtills.decrypt(wxLoginVo.getEncryptData(), sessionKey, wxLoginVo.getIv());
JSONObject jsonObject1 = JSONObject.parseObject(data);
String phoneNumber =jsonObject1.getString("phoneNumber");
if (StringUtils.isEmpty(phoneNumber)) {
return new JsonResult().setMsg("未获取到手机号,登录失败");
}
CuCustomer cuCustomer = cuCustomerService.checkMobile(phoneNumber);
if (cuCustomer == null) {
//            注册
cuCustomer = cuCustomerService.regist3(openId, phoneNumber, wxLoginVo.getNickname(), wxLoginVo.getAvatar());
} else {
//        写入微信openid
if (StringUtils.isEmpty(cuCustomer.getWxOpenId())) {
cuCustomer.setWxOpenId(openId);
}
cuCustomer.setWxAvatar(wxLoginVo.getAvatar());
cuCustomerService.update(cuCustomer);
}
//        登录
String token = JWTUtil.sign(phoneNumber, JWTToken.SOURCE_PC, JWTToken.TYPE_CUSTOMER, cuCustomer.getPassword());
redisService.save(JWTUtil.getCustomerRefreshTimeKey(token), JSON.toJSONString(cuCustomer), JWTUtil.REFRESH_TIME);
redisService.save(JWTUtil.getCustomerUserKey(token), JSON.toJSONString(cuCustomer), JWTUtil.EXPIRE_TIME);
//防止用户多端登录,产生多个token
String oldTokenStr = redisService.get("LOGINCUCUSTOMER:" + cuCustomer.getId());
if (StringUtils.isNotEmpty(oldTokenStr)) {
JWTToken oldToken = new JWTToken(oldTokenStr);
redisService.delete("JWT:token:" + oldToken.getSource() + ":" + oldToken.getType() + ":refreshTime:" + oldToken.getSignId());
redisService.delete("JWT:token:" + oldToken.getSource() + ":" + oldToken.getType() + ":user:" + oldToken.getSignId());
}
redisService.save("LOGINCUCUSTOMER:" + cuCustomer.getId(), token);
HashMap<String, Object> map = new HashMap<>();
map.put("token", token);
return new JsonResult().setSuccess(true).setObj(map);
}
}

注意:老版调用过程中一定要先调用uni.login(),再去触发button获取手机号,不然会导致sessionKey失效,从而使得后端解密失败。

微信小程序文档

总结

到此

您可能感兴趣的文章:微信小程序中获取用户手机号授权登录详细步骤

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:手机app制作平台哪个好
下一篇:商城APP能给企业带来哪些优势
相关文章

 发表评论

暂时没有评论,来抢沙发吧~