前言
小程序可以通過(guò)微信官方提供的登錄能力方便地獲取微信提供的用戶身份標(biāo)識(shí),快速建立小程序內(nèi)的用戶體系
?一.微信授權(quán)登錄工作流程
1.理論敘述
-
觸發(fā)授權(quán)登錄: 用戶在小程序中觸發(fā)登錄操作,通常通過(guò)點(diǎn)擊登錄按鈕或執(zhí)行相關(guān)操作。
-
授權(quán)彈窗: 小程序彈出授權(quán)登錄的彈窗,要求用戶授權(quán)小程序訪問(wèn)其微信賬號(hào)信息。
-
用戶選擇授權(quán): 用戶可以選擇授權(quán)或拒絕授權(quán)。如果用戶拒絕,登錄流程終止。
-
獲取登錄憑證: 如果用戶選擇授權(quán),小程序會(huì)獲得一個(gè)臨時(shí)的
code
。 -
向后臺(tái)服務(wù)器發(fā)送登錄憑證: 小程序?qū)?
code
發(fā)送到自己的后臺(tái)服務(wù)器。 -
后臺(tái)服務(wù)器與微信服務(wù)器通信: 后臺(tái)服務(wù)器使用
code
向微信服務(wù)器發(fā)送請(qǐng)求,請(qǐng)求中包括小程序的 AppID、AppSecret 和code
。 -
微信服務(wù)器響應(yīng): 微信服務(wù)器會(huì)驗(yàn)證
code
的合法性,并在驗(yàn)證通過(guò)后,返回用戶的唯一標(biāo)識(shí)符openid
和會(huì)話密鑰session_key
。 -
后臺(tái)服務(wù)器驗(yàn)證身份: 后臺(tái)服務(wù)器通常會(huì)驗(yàn)證
openid
和session_key
的有效性,以確保用戶的身份合法。這一步也可以用于防止濫用和欺詐。 -
用戶數(shù)據(jù)加解密: 小程序使用
session_key
來(lái)加密和解密用戶的數(shù)據(jù),以保護(hù)用戶的隱私。 -
執(zhí)行業(yè)務(wù)邏輯: 一旦用戶登錄成功,小程序可以執(zhí)行與用戶身份相關(guān)的業(yè)務(wù)邏輯,如顯示個(gè)性化內(nèi)容、保存用戶操作記錄等。
-
保護(hù)用戶隱私: 小程序必須尊重用戶隱私,僅獲取有限的用戶信息,不包括敏感信息。
-
用戶退出: 提供用戶注銷或取消授權(quán)的選項(xiàng),以允許用戶隨時(shí)退出登錄。
2.圖文詳解
二.微信授權(quán)登錄案例講解
1.準(zhǔn)備配置
1.1 前端接口調(diào)用地址
// 以下是業(yè)務(wù)服務(wù)器API地址
// 本機(jī)開(kāi)發(fā)API地址
var WxApiRoot = 'http://localhost:8080/oapro/wx/';
// 測(cè)試環(huán)境部署api地址
// var WxApiRoot = 'http://192.168.191.1:8080/oapro/wx/';
// 線上平臺(tái)api地址
//var WxApiRoot = 'https://www.oa-mini.com/demo/wx/';
module.exports = {
IndexUrl: WxApiRoot + 'home/index', //首頁(yè)數(shù)據(jù)接口
SwiperImgs: WxApiRoot+'swiperImgs',
MettingInfos: WxApiRoot+'meeting/list',
AuthLoginByWeixin: WxApiRoot + 'auth/login_by_weixin', //微信登錄
UserIndex: WxApiRoot + 'user/index', //個(gè)人頁(yè)面用戶相關(guān)信息
AuthLogout: WxApiRoot + 'auth/logout', //賬號(hào)登出
AuthBindPhone: WxApiRoot + 'auth/bindPhone' //綁定微信手機(jī)號(hào)
};
1.2 封裝微信調(diào)用request
/**
* 封封微信的的request
*/
function request(url, data = {}, method = "GET") {
return new Promise(function (resolve, reject) {
wx.request({
url: url,
data: data,
method: method,
timeout:3000,
header: {
'Content-Type': 'application/json',
'X-OA-Token': wx.getStorageSync('token')
},
success: function (res) {
if (res.statusCode == 200) {
if (res.data.errno == 501) {
// 清除登錄相關(guān)內(nèi)容
try {
wx.removeStorageSync('userInfo');
wx.removeStorageSync('token');
} catch (e) {
// Do something when catch error
}
// 切換到登錄頁(yè)面
wx.navigateTo({
url: '/pages/auth/login/login'
});
} else {
resolve(res.data);
}
} else {
reject(res.errMsg);
}
},
fail: function (err) {
reject(err)
}
})
});
}
function redirect(url) {
//判斷頁(yè)面是否需要登錄
if (false) {
wx.redirectTo({
url: '/pages/auth/login/login'
});
return false;
} else {
wx.redirectTo({
url: url
});
}
}
1.3?配置數(shù)據(jù)庫(kù)及小程序和小程序密鑰
?
2.點(diǎn)擊觸發(fā)授權(quán)登錄
3.登錄流程
代碼流程解釋:授權(quán)彈窗后會(huì)獲取我們的用戶信息,通過(guò)登錄判斷我們是否登錄過(guò),若沒(méi)有,則調(diào)用微信登錄的函數(shù)進(jìn)行登錄操作,首先,將用戶信息以參數(shù)的形式進(jìn)行傳遞,通過(guò)用戶信息向遠(yuǎn)程服務(wù)器(后端)發(fā)送請(qǐng)求,并攜帶授權(quán)登錄時(shí)的臨時(shí)code值,再通過(guò)調(diào)用微信的授權(quán)登錄接口,將code值進(jìn)行傳入,然后返回一個(gè)結(jié)果對(duì)象,通過(guò)當(dāng)前對(duì)象獲取我們的session_key和openid(唯一標(biāo)識(shí)),通過(guò)當(dāng)前的openid可以獲取到我們的用戶信息判斷我們是否之前登錄過(guò)當(dāng)前小程序,并將登錄信息存儲(chǔ)到數(shù)據(jù)庫(kù)中,且將我們的登錄時(shí)間進(jìn)行更新
2.1 前端函數(shù)代碼
getUserProfile(e) {
// 推薦使用wx.getUserProfile獲取用戶信息,開(kāi)發(fā)者每次通過(guò)該接口獲取用戶個(gè)人信息均需用戶確認(rèn)
// 開(kāi)發(fā)者妥善保管用戶快速填寫的頭像昵稱,避免重復(fù)彈窗
wx.getUserProfile({
desc: '用于完善會(huì)員資料', // 聲明獲取用戶個(gè)人信息后的用途,后續(xù)會(huì)展示在彈窗中,請(qǐng)謹(jǐn)慎填寫
success: (res) => {
//console.log(res);
debugger
user.checkLogin().catch(() => {
user.loginByWeixin(res.userInfo).then(res => {
app.globalData.hasLogin = true;
debugger
wx.navigateBack({
delta: 1
})
}).catch((err) => {
app.globalData.hasLogin = false;
if(err.errMsg=="request:fail timeout"){
util.showErrorToast('微信登錄超時(shí)');
}else{
util.showErrorToast('微信登錄失敗');
}
this.setData({
lock:false
})
});
});
},
fail: (res) => {
app.globalData.hasLogin = false;
console.log(res);
util.showErrorToast('微信登錄失敗');
}
});
},
2.2 后端邏輯代碼
?
@PostMapping("login_by_weixin")
public Object loginByWeixin(@RequestBody WxLoginInfo wxLoginInfo, HttpServletRequest request) {
//客戶端需攜帶code與userInfo信息
String code = wxLoginInfo.getCode();
UserInfo userInfo = wxLoginInfo.getUserInfo();
if (code == null || userInfo == null) {
return ResponseUtil.badArgument();
}
//調(diào)用微信sdk獲取openId及sessionKey
String sessionKey = null;
String openId = null;
try {
long beginTime = System.currentTimeMillis();
//
WxMaJscode2SessionResult result = this.wxService.getUserService().getSessionInfo(code);
// Thread.sleep(6000);
long endTime = System.currentTimeMillis();
log.info("響應(yīng)時(shí)間:{}",(endTime-beginTime));
sessionKey = result.getSessionKey();//session id
openId = result.getOpenid();//用戶唯一標(biāo)識(shí) OpenID
} catch (Exception e) {
e.printStackTrace();
}
if (sessionKey == null || openId == null) {
log.error("微信登錄,調(diào)用官方接口失?。簕}", code);
return ResponseUtil.fail();
}else{
log.info("openId={},sessionKey={}",openId,sessionKey);
}
//根據(jù)openId查詢wx_user表
//如果不存在,初始化wx_user,并保存到數(shù)據(jù)庫(kù)中
//如果存在,更新最后登錄時(shí)間
WxUser user = userService.queryByOid(openId);
if (user == null) {
user = new WxUser();
user.setUsername(openId);
user.setPassword(openId);
user.setWeixinOpenid(openId);
user.setAvatar(userInfo.getAvatarUrl());
user.setNickname(userInfo.getNickName());
user.setGender(userInfo.getGender());
user.setUserLevel((byte) 0);
user.setStatus((byte) 0);
user.setLastLoginTime(new Date());
user.setLastLoginIp(IpUtil.client(request));
user.setShareUserId(1);
userService.add(user);
} else {
user.setLastLoginTime(new Date());
user.setLastLoginIp(IpUtil.client(request));
if (userService.updateById(user) == 0) {
log.error("修改失?。簕}", user);
return ResponseUtil.updatedDataFailed();
}
}
// token
UserToken userToken = null;
try {
userToken = UserTokenManager.generateToken(user.getId());
} catch (Exception e) {
log.error("微信登錄失敗,生成token失?。簕}", user.getId());
e.printStackTrace();
return ResponseUtil.fail();
}
userToken.setSessionKey(sessionKey);
log.info("SessionKey={}",UserTokenManager.getSessionKey(user.getId()));
Map<Object, Object> result = new HashMap<Object, Object>();
result.put("token", userToken.getToken());
result.put("tokenExpire", userToken.getExpireTime().toString());
userInfo.setUserId(user.getId());
if (!StringUtils.isEmpty(user.getMobile())) {// 手機(jī)號(hào)存在則設(shè)置
userInfo.setPhone(user.getMobile());
}
try {
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
String registerDate = df.format(user.getAddTime() != null ? user.getAddTime() : new Date());
userInfo.setRegisterDate(registerDate);
userInfo.setStatus(user.getStatus());
userInfo.setUserLevel(user.getUserLevel());// 用戶層級(jí)
userInfo.setUserLevelDesc(UserTypeEnum.getInstance(user.getUserLevel()).getDesc());// 用戶層級(jí)描述
} catch (Exception e) {
log.error("微信登錄:設(shè)置用戶指定信息出錯(cuò):"+e.getMessage());
e.printStackTrace();
}
result.put("userInfo", userInfo);
log.info("【請(qǐng)求結(jié)束】微信登錄,響應(yīng)結(jié)果:{}", JSONObject.toJSONString(result));
return ResponseUtil.ok(result);
}
2.3 token
由上述代碼可知,我們的末尾中獲取當(dāng)前token令牌,由于我們前面通過(guò)openid獲取到所有的用戶信息,包括我們的用戶id,然后我們就可以使用這個(gè)用戶id去生成一個(gè)專屬的token令牌,并響應(yīng)到前端,存儲(chǔ)到我們的請(qǐng)求頭中,具體了解token令牌詳解請(qǐng)看往期博客,有詳解一篇文章讓你了解“JWT“
@GetMapping("index")
public Object list(@LoginUser Integer userId, @RequestHeader("X-OA-token") String token) {
log.info("【請(qǐng)求開(kāi)始】用戶個(gè)人頁(yè)面數(shù)據(jù),請(qǐng)求參數(shù),userId:{}", userId);
log.info("【請(qǐng)求開(kāi)始】用戶個(gè)人頁(yè)面數(shù)據(jù),請(qǐng)求參數(shù),token:{}", token);
if (userId == null) {
log.error("用戶個(gè)人頁(yè)面數(shù)據(jù)查詢失敗:用戶未登錄?。?!");
return ResponseUtil.unlogin();
}
WxUser wxUser = userService.selectByPrimaryKey(userId);
Map<Object, Object> data = new HashMap<Object, Object>();
data.put("metting_pubs", wxUser.getUserLevel());
data.put("metting_joins",wxUser.getUserLevel());
return ResponseUtil.ok(data);
}
?4.效果演示
3.1 登錄時(shí)間更新
三.退出登錄
前端向后端發(fā)送退出登錄請(qǐng)求,后端通過(guò)判斷userid將我們的token令牌進(jìn)行銷毀,防止被他人利用token令牌向服務(wù)器發(fā)送惡意請(qǐng)求,保證安全性
/**
* 注銷登錄
*/
@PostMapping("logout")
public Object logout(@LoginUser Integer userId) {
log.info("【請(qǐng)求開(kāi)始】注銷登錄,請(qǐng)求參數(shù),userId:{}", userId);
if (userId == null) {
return ResponseUtil.unlogin();
}
try {
UserTokenManager.removeToken(userId);
} catch (Exception e) {
log.error("注銷登錄出錯(cuò):userId:{}", userId);
e.printStackTrace();
return ResponseUtil.fail();
}
log.info("【請(qǐng)求結(jié)束】注銷登錄成功!");
return ResponseUtil.ok();
}
今天的分享到這里就結(jié)束了,感謝各位大大的觀看,各位大大的三連是博主更新的動(dòng)力,感謝謝謝謝謝謝謝謝謝各位的支持?。。。。??文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-713014.html
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-713014.html
到了這里,關(guān)于微信小程序-微信授權(quán)登錄的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!