小程序自身攜帶龐大流量基显,又提供了各種強大的API,今天只說授權登錄善炫。以前可以直接默認調起授權撩幽,最近在做的時候發(fā)現(xiàn)改版了,需要用戶手動觸發(fā)授權按鈕箩艺。
1摸航、login.wxml
<button wx:if="{{canIUse}}" open-type="getUserInfo" bindgetuserinfo="bindGetUserInfo" class="weui-btn" type="primary" style='margin-top:15%'>授權登錄</button>
<view wx:else>請升級微信版本</view>
判斷是否授權,如果沒有舅桩,則顯示授權按鈕酱虎。注意上面的open-type="getUserInfo",這個會自動調起授權框擂涛《链看一下js
// pages/login/login.js
var util = require('../../utils/util.js');
Page({
/**
* 頁面的初始數(shù)據
*/
data: {
canIUse: wx.canIUse('button.open-type.getUserInfo')
},
bindGetUserInfo: function (e) {
if (e.detail.userInfo) {
// 登錄
wx.login({
success: res => {
// 發(fā)送 res.code 到后臺換取 openId, sessionKey, unionId
wx.request({
url: '{你的https域名}/api/login/applet',
data: { code: res.code },
method: 'POST',
header: { 'content-type': 'application/x-www-form-urlencoded' },
success: function (res1) {
wx.setStorageSync("sessionId", res1.data.data);
wx.getUserInfo({
success: res => {
// 可以將 res 發(fā)送給后臺解碼出 unionId
wx.request({
url: '{你的https域名}/api/login/user-info',
data: {
encryptedData: res.encryptedData,
iv: res.iv,
sessionId: wx.getStorageSync("sessionId")
},
method: 'POST',
header: { 'content-type': 'application/x-www-form-urlencoded' },
success: function (res1) {
wx.setStorageSync("storeMemberId", res1.data.data.id);
var member = res1.data.data;
//這里獲取到了用戶信息,可以執(zhí)行自己的操作
wx.switchTab({
url: '/pages/index/index',
})
}
})
}
})
}
})
}
})
//用戶按了允許授權按鈕
} else {
//用戶按了拒絕按鈕
wx.redirectTo({
url: '/pages/login/login',
})
}
}
})
2撒妈、后臺獲取用戶信息
基本流程:拿到上面js獲取的code換取openid和session_key恢暖,如果你只需要openid,下面這一步就夠了狰右。
下面可以看到杰捂,我把獲取到的session_key放redis了,因為我需要用它獲取用戶詳情棋蚌。
@ResponseBody
@RequestMapping("applet")
public ResultModel<String> login4applet(String code) {
try {
String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + AppletInfo.appid + "&secret=" + AppletInfo.secret +
"&js_code=" + code + "&grant_type=authorization_code";
String res = HttpClientUtil.post(url);
Map<String,String> data = FastJsonUtils.toBean(res,Map.class);
String openid = data.get("openid");
String session_key = data.get("session_key");
String sessionId = IDGen.genId();
stringRedisTemplate.opsForValue().set(sessionId, session_key + "," + openid,7200,TimeUnit.SECONDS);
return new ResultModel<>(ResultStatus.SUCCESS, sessionId);
} catch (NormalException e) {
return ResultModel.defaultError("授權失敗");
}
}
3嫁佳、換取用戶信息
第一步中第一個ajax請求后,又發(fā)送一次請求谷暮,三個參數(shù)
encryptedData: 加密數(shù)據
iv:偏移
sessionId: 上面第二步的sessionId蒿往,其實就是一個標識
通過sessionId取到上面存在redis中的sessionKey,因為官方建議最好不要直接傳輸這個湿弦,因此我用了本地緩存瓤漏。
@ResponseBody
@RequestMapping("user-info")
public ResultModel<Member> getUserInfo(String sessionId, String iv, String encryptedData) {
String sessionKeyAndOpenId = stringRedisTemplate.opsForValue().get(sessionId);
if (StringUtil.isBlank(sessionKeyAndOpenId)) {
throw new NormalException("登錄信息失效");
}
String sessionKey = sessionKeyAndOpenId.split(",")[0];
// 被加密的數(shù)據
try {
byte[] dataByte = Base64.decode(encryptedData);
// 加密秘鑰
byte[] keyByte = Base64.decode(sessionKey);
// 偏移量
byte[] ivByte = Base64.decode(iv);
String result = AESUtil.decrypt(dataByte, keyByte, ivByte);
Map<String, String> map = FastJsonUtils.toBean(result, HashMap.class);
if (map.get("openId") == null) {
throw new NormalException("獲取用戶信息失敗");
}
//先判斷是否存在unionId
String unionId =map.get("unionId");
ResultModel<Member> resultModel = memberService.getByUnionId(unionId);
Member member = resultModel.getData();
if (member == null){
String openId = map.get("openId");
member.setOpenId(openId);
String avatarUrl = map.get("avatarUrl");
member = new Member();
member.setId(IDGen.genId());
member.setUnionId(unionId);
memberService.save(member);
}
return new ResultModel<>(ResultStatus.SUCCESS, member);
} catch (NormalException e) {
return new ResultModel<>(ResultStatus.FAIL, null);
}
}
此時我們已經獲取了用戶的openid,unionId(如果綁定了開放平臺的話)颊埃,頭像蔬充,昵稱,省市等信息班利,剩下的就自己隨便玩兒了
4饥漫、爬坑
既然寫代碼,沒坑怎么行肥败?
Q:報錯:invalid appid
A:可是建項目開始就綁定了appid啊趾浅,原來在通過code獲取session_key的時候,不小心發(fā)成了get請求馒稍。
ps:鄙視一下騰訊的同行皿哨,你這時候是不是提示method not support更合適呢?害的我找了半天bug~~~
其實整體來說根據api一步一步來還是沒什么問題的纽谒,就是他的文檔有的寫的確實有點坑证膨,希望踩過的童鞋一起來吐槽~~~