uniapp微信小程序授權(quán)登錄并獲取手機(jī)號(hào)的方法
新版:前端要授權(quán)兩次,一次獲取用戶信息授權(quán)碼code,另外一次獲取用戶手機(jī)授權(quán)碼code,全部傳給后端。后端通過(guò)用戶信息授權(quán)碼獲取openid,通過(guò)手機(jī)授權(quán)碼獲取手機(jī)號(hào)碼。老版:前端傳給后端授權(quán)碼code和用戶手機(jī)授權(quán)回調(diào) 里的iv和encryptedData給后端,后端通過(guò)code獲取openid和sessionKey,然后他用sessionKey和iv解密encryptedData獲取手機(jī)號(hào)。最后通過(guò)手機(jī)號(hào)進(jìn)行綁定用戶,然后通過(guò)登錄驗(yàn)證返回給前端登錄憑證token。
登錄邏輯
新版
1.調(diào)用uni.login()獲取code1
2.用戶主動(dòng)觸發(fā)button按鈕在回調(diào)getPhoneNumber獲取code2
<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber"></button>
Page({
getPhoneNumber (e) {
console.log(e.detail.code)
}
})3.后端拿到code1獲取openid ,code2獲取手機(jī)號(hào)碼(代碼在api里面)
老版
1.先在onshow()生命周期中獲取code
2.用戶主動(dòng)觸發(fā)button按鈕在回調(diào)getPhoneNumber獲取iv和encryptedData
<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber"></button>
Page({
getPhoneNumber (e) {
console.log(e.detail.errMsg)
console.log(e.detail.iv)
console.log(e.detail.encryptedData)
}
})3.后端拿到code、iv、encryptedData,然后code獲取openid和sessionKey,然后通過(guò)sessionKey和iv解密encryptedData獲取到手機(jī)號(hào)
獲取得到的解密數(shù)據(jù)為以下 json 結(jié)構(gòu):
{
"phoneNumber": "13580006666",
"purePhoneNumber": "13580006666",
"countryCode": "86",
"watermark":
{
"appid":"APPID",
"timestamp": TIMESTAMP
}
}解密工具類
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數(shù)據(jù)
*/
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 加密數(shù)據(jù)
* @param sessionKey 會(huì)話密鑰
* @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
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("返回值為空,請(qǐng)檢查請(qǐng)求報(bào)文或者請(qǐng)求地址是否正確");
}
} catch (Exception e) {
e.printStackTrace();
}
return accessToken;
}
/**
* 獲取手機(jī)號(hào)
*/
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("獲取微信手機(jī)號(hào)碼:{}", 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("返回值為空,請(qǐng)檢查請(qǐng)求報(bào)文或者請(qǐng)求地址是否正確");
}
} 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("返回值為空,請(qǐng)檢查請(qǐng)求報(bào)文或者請(qǐng)求地址是否正確");
}
} 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("未獲取到手機(jī)號(hào),登錄失敗");
}
CuCustomer cuCustomer = cuCustomerService.checkMobile(phoneNumber);
if (cuCustomer == null) {
// 注冊(cè)
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);
//防止用戶多端登錄,產(chǎn)生多個(gè)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);
}
}注意:老版調(diào)用過(guò)程中一定要先調(diào)用uni.login(),再去觸發(fā)button獲取手機(jī)號(hào),不然會(huì)導(dǎo)致sessionKey失效,從而使得后端解密失敗。
總結(jié)
到此這篇關(guān)于uniapp微信小程序授權(quán)登錄并獲取手機(jī)號(hào)的文章就介紹到這了,更多相關(guān)uniapp微信小程序授權(quán)登錄內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
jQuery及JS實(shí)現(xiàn)循環(huán)中暫停的方法
這篇文章主要介紹了jQuery及JS實(shí)現(xiàn)循環(huán)中暫停的方法,以實(shí)例形式分析了循環(huán)中暫停的原理及實(shí)現(xiàn)技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-02-02
js判斷傳入時(shí)間和當(dāng)前時(shí)間大小實(shí)例(超簡(jiǎn)單)
下面小編就為大家分享一篇js判斷傳入時(shí)間和當(dāng)前時(shí)間大小實(shí)例(超簡(jiǎn)單),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-01-01
js實(shí)現(xiàn)頭像圖片切割縮放及無(wú)刷新上傳圖片的方法
這篇文章主要介紹了js實(shí)現(xiàn)頭像圖片切割縮放及無(wú)刷新上傳圖片的方法,涉及javascript結(jié)合php實(shí)現(xiàn)文件無(wú)刷新上傳等相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-07-07
輕松玩轉(zhuǎn)BootstrapTable(后端使用SpringMVC+Hibernate)
這篇文章主要和大家輕松玩轉(zhuǎn)BootstrapTable,后端使用SpringMVC+Hibernate,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-09-09
通過(guò)繼承IHttpHandle實(shí)現(xiàn)JS插件的組織與管理
最近,項(xiàng)目中的用到的Js插件越來(lái)越多,有的是用原生javascript寫的,有的是調(diào)用的jquery插件,頁(yè)面上Js和Css文件的引用也越來(lái)越混亂,而且Js文件之間還有引用先后的依賴關(guān)系2010-07-07
使用javascript函數(shù)編寫簡(jiǎn)單銀行取錢存錢流程
本文通過(guò)實(shí)例代碼給大家講解了使用javascript函數(shù)編寫簡(jiǎn)單銀行取錢存錢流程,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2018-05-05
location.href 在IE6中不跳轉(zhuǎn)的解決方法與推薦使用代碼
在js中,我們經(jīng)常使用location.href來(lái)實(shí)現(xiàn)頁(yè)面的跳轉(zhuǎn),為了方便我們寫成函數(shù)。下面就分別說(shuō)明下,下面的一些代碼的實(shí)現(xiàn)問(wèn)題。2010-07-07
JavaScript中setInterval的用法總結(jié)
這篇文章主要是對(duì)JavaScript中setInterval的用法進(jìn)行了詳細(xì)的總結(jié)介紹,需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助2013-11-11

