????歡迎來到我的CSDN主頁!????
??我是Java方文山,一個在CSDN分享筆記的博主。????
??推薦給大家我的專欄《微信小程序開發(fā)實戰(zhàn)》。????
??點擊這里,就可以查看我的主頁啦!????
Java方文山的個人主頁
??如果感覺還不錯的話請給我點贊吧!????
??期待你的加入,一起學習,一起進步!????
一、微信授權登錄流程
小程序登錄
小程序可以通過微信官方提供的登錄能力方便地獲取微信提供的用戶身份標識,快速建立小程序內的用戶體系。
????圖解????
步驟流程:
1.小程序調用wx.login() 獲取 臨時登錄憑證code ,并回傳到開發(fā)者服務器
2.開發(fā)者服務器以appid+appsecret+code換取 用戶唯一標識openid和會話密鑰session_key。
3.開發(fā)者服務器根據(jù)用戶標識來生成自定義登錄態(tài)用于后續(xù)業(yè)務邏輯中前后端交互時識別用戶身份
4.客戶端保存后端生成的自定義登錄態(tài),并在下一次發(fā)送請求的時候帶上這個自定義登錄態(tài)。
注意:臨時登錄憑證code只能使用一次
二、微信用戶授權
下面我以兩種方式的代碼來給大家論證一下微信用戶授權登錄的流程,第一種不需要用戶確認即可完成用戶授權登錄在開發(fā)中并不是那么的安全,第二種則是需要用戶確認方可進行授權登錄。
前期準備工作
wxml代碼展示
<!--pages/index/index.wxml-->
<view>
<button wx:if="{{canIUseGetUserProfile}}" type="primary" class="wx-login-btn" bindtap="getUserProfile">微信直接登錄1</button>
<button wx:else open-type="getUserInfo" type="primary" class="wx-login-btn" bindgetuserinfo="wxLogin">微信直接登錄2</button>
<image mode="scaleToFill" src="{{userInfo.avatarUrl}}" />
<text>昵稱:{{userInfo.nickName}}</text>
</view>
1.wx.login
JS代碼展示
wxLogin: function(e) {
debugger
console.log('wxLogin')
console.log(e.detail.userInfo);
this.setData({
userInfo: e.detail.userInfo
})
if (e.detail.userInfo == undefined) {
app.globalData.hasLogin = false;
util.showErrorToast('微信登錄失敗');
return;
}
效果展示:
看得出確實是走的這個方法并獲取用戶信息的,我們繼續(xù)看一下另一個方法。
2.wx.getUserProfile
JS代碼展示
getUserProfile(e) {
console.log('getUserProfile')
// 推薦使用 wx.getUserProfile 獲取用戶信息,開發(fā)者每次通過該接口獲取用戶個人信息均需用戶確認
// 開發(fā)者妥善保管用戶快速填寫的頭像昵稱,避免重復彈窗
wx.getUserProfile({
desc: '用于完善會員資料', // 聲明獲取用戶個人信息后的用途,后續(xù)會展示在彈窗中,請謹慎填寫
success: (res) => {
console.log(res);
this.setData({
userInfo: res.userInfo,
hasUserInfo: true
})
}
})
}
效果展示:?
3.用戶授權完成后端交互?
我們使用用戶授權后將用戶信息保存到數(shù)據(jù)庫方便下次用戶發(fā)送請求的時候做身份認證。
封裝的代碼
utils/util.js
function formatTime(date) {
var year = date.getFullYear()
var month = date.getMonth() + 1
var day = date.getDate()
var hour = date.getHours()
var minute = date.getMinutes()
var second = date.getSeconds()
return [year, month, day].map(formatNumber).join('-') + ' ' + [hour, minute, second].map(formatNumber).join(':')
}
function formatNumber(n) {
n = n.toString()
return n[1] ? n : '0' + n
}
/**
* 封封微信的的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) {
// 清除登錄相關內容
try {
wx.removeStorageSync('userInfo');
wx.removeStorageSync('token');
} catch (e) {
// Do something when catch error
}
// 切換到登錄頁面
wx.navigateTo({
url: '/pages/auth/login/login'
});
} else {
resolve(res.data);
}
} else {
reject(res.errMsg);
}
},
fail: function (err) {
reject(err)
}
})
});
}
function redirect(url) {
//判斷頁面是否需要登錄
if (false) {
wx.redirectTo({
url: '/pages/auth/login/login'
});
return false;
} else {
wx.redirectTo({
url: url
});
}
}
function showErrorToast(msg) {
wx.showToast({
title: msg,
image: '/static/images/icon_error.png'
})
}
function jhxLoadShow(message) {
if (wx.showLoading) { // 基礎庫 1.1.0 微信6.5.6版本開始支持,低版本需做兼容處理
wx.showLoading({
title: message,
mask: true
});
} else { // 低版本采用Toast兼容處理并將時間設為20秒以免自動消失
wx.showToast({
title: message,
icon: 'loading',
mask: true,
duration: 20000
});
}
}
function jhxLoadHide() {
if (wx.hideLoading) { // 基礎庫 1.1.0 微信6.5.6版本開始支持,低版本需做兼容處理
wx.hideLoading();
} else {
wx.hideToast();
}
}
module.exports = {
formatTime,
request,
redirect,
showErrorToast,
jhxLoadShow,
jhxLoadHide
}
config/api.js?
// 以下是業(yè)務服務器API地址
// 本機開發(fā)API地址
var WxApiRoot = 'http://localhost:8080/oapro/wx/';
// 測試環(huán)境部署api地址
// var WxApiRoot = 'http://192.168.191.1:8080/oapro/wx/';
// 線上平臺api地址
//var WxApiRoot = 'https://www.oa-mini.com/demo/wx/';
module.exports = {
IndexUrl: WxApiRoot + 'home/index', //首頁數(shù)據(jù)接口
SwiperImgs: WxApiRoot+'swiperImgs',
MettingInfos: WxApiRoot+'meeting/list',
AuthLoginByWeixin: WxApiRoot + 'auth/login_by_weixin', //微信登錄
UserIndex: WxApiRoot + 'user/index', //個人頁面用戶相關信息
AuthLogout: WxApiRoot + 'auth/logout', //賬號登出
AuthBindPhone: WxApiRoot + 'auth/bindPhone' //綁定微信手機號
};
JS代碼
// pages/auth/login/login.js
var util = require('../../../utils/util.js');
var user = require('../../../utils/user.js');
const app = getApp();
Page({
/**
* 頁面的初始數(shù)據(jù)
*/
data: {
canIUseGetUserProfile: false, // 用于向前兼容
lock:false
},
onLoad: function(options) {
// 頁面初始化 options為頁面跳轉所帶來的參數(shù)
// 頁面渲染完成
if (wx.getUserProfile) {
this.setData({
canIUseGetUserProfile: true
})
}
//console.log('login.onLoad.canIUseGetUserProfile='+this.data.canIUseGetUserProfile)
},
/**
* 生命周期函數(shù)--監(jiān)聽頁面初次渲染完成
*/
onReady() {
},
/**
* 生命周期函數(shù)--監(jiān)聽頁面顯示
*/
onShow() {
},
getUserProfile(e) {
console.log('getUserProfile');
// 推薦使用wx.getUserProfile獲取用戶信息,開發(fā)者每次通過該接口獲取用戶個人信息均需用戶確認
// 開發(fā)者妥善保管用戶快速填寫的頭像昵稱,避免重復彈窗
wx.getUserProfile({
desc: '用于完善會員資料', // 聲明獲取用戶個人信息后的用途,后續(xù)會展示在彈窗中,請謹慎填寫
success: (res) => {
//console.log(res);
user.checkLogin().catch(() => {
user.loginByWeixin(res.userInfo).then(res => {
app.globalData.hasLogin = true;
wx.navigateBack({
delta: 1
})
}).catch((err) => {
app.globalData.hasLogin = false;
if(err.errMsg=="request:fail timeout"){
util.showErrorToast('微信登錄超時');
}else{
util.showErrorToast('微信登錄失敗');
}
this.setData({
lock:false
})
});
});
},
fail: (res) => {
app.globalData.hasLogin = false;
console.log(res);
util.showErrorToast('微信登錄失敗');
}
});
},
wxLogin: function(e) {
console.log('wxLogin');
if (e.detail.userInfo == undefined) {
app.globalData.hasLogin = false;
util.showErrorToast('微信登錄失敗');
return;
}
user.checkLogin().catch(() => {
user.loginByWeixin(e.detail.userInfo).then(res => {
app.globalData.hasLogin = true;
wx.navigateBack({
delta: 1
})
}).catch((err) => {
app.globalData.hasLogin = false;
if(err.errMsg=="request:fail timeout"){
util.showErrorToast('微信登錄超時');
}else{
util.showErrorToast('微信登錄失敗');
}
});
});
},
accountLogin() {
console.log('開發(fā)中....')
}
})
WXML代碼
<view class="container">
<view class="login-box">
<button wx:if="{{canIUseGetUserProfile}}" type="primary" class="wx-login-btn" bindtap="getUserProfile">微信直接登錄</button>
<button wx:else open-type="getUserInfo" type="primary" class="wx-login-btn" bindgetuserinfo="wxLogin">微信直接登錄</button>
<button type="primary" class="account-login-btn" bindtap="accountLogin">賬號登錄</button>
</view>
</view>
?后端配置appid+appsecret與數(shù)據(jù)庫連接
后端代碼
/**
* 微信登錄
*
* @param wxLoginInfo
* 請求內容,{ code: xxx, userInfo: xxx }
* @param request
* 請求對象
* @return 登錄結果
*/
@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();
}
//調用微信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("響應時間:{}",(endTime-beginTime));
sessionKey = result.getSessionKey();//session id
openId = result.getOpenid();//用戶唯一標識 OpenID
} catch (Exception e) {
e.printStackTrace();
}
if (sessionKey == null || openId == null) {
log.error("微信登錄,調用官方接口失?。簕}", code);
return ResponseUtil.fail();
}else{
log.info("openId={},sessionKey={}",openId,sessionKey);
}
//根據(jù)openId查詢wx_user表
//如果不存在,初始化wx_user,并保存到數(shù)據(jù)庫中
//如果存在,更新最后登錄時間
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())) {// 手機號存在則設置
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());// 用戶層級
userInfo.setUserLevelDesc(UserTypeEnum.getInstance(user.getUserLevel()).getDesc());// 用戶層級描述
} catch (Exception e) {
log.error("微信登錄:設置用戶指定信息出錯:"+e.getMessage());
e.printStackTrace();
}
result.put("userInfo", userInfo);
log.info("【請求結束】微信登錄,響應結果:{}", JSONObject.toJSONString(result));
return ResponseUtil.ok(result);
}
?數(shù)據(jù)庫展示
效果演示
三、微信手機號授權
手機授權原理也是如此只不過調用的接口不同罷了。
JS代碼
var util = require('../../../utils/util.js');
var api = require('../../../config/api.js');
var user = require('../../../utils/user.js');
var app = getApp();
Page({
/**
* 頁面的初始數(shù)據(jù)
*/
data: {
userInfo: {},
hasLogin: false,
userSharedUrl: ''
},
/**
* 生命周期函數(shù)--監(jiān)聽頁面加載
*/
onLoad: function (options) {
},
onShow: function () {
let that = this;
//獲取用戶的登錄信息
let userInfo = wx.getStorageSync('userInfo');
this.setData({
userInfo: userInfo,
hasLogin: true
});
},
getPhoneNumber: function (e) {
console.log(e);
let that = this;
if (e.detail.errMsg !== "getPhoneNumber:ok") {
// 拒絕授權
return;
}
if (!this.data.hasLogin) {
wx.showToast({
title: '綁定失敗:請先登錄',
icon: 'none',
duration: 2000
});
return;
}
util.request(api.AuthBindPhone, {
iv: e.detail.iv,
encryptedData: e.detail.encryptedData
}, 'POST').then(function (res) {
if (res.errno === 0) {
let userInfo = wx.getStorageSync('userInfo');
userInfo.phone = res.data.phone;//設置手機號碼
wx.setStorageSync('userInfo', userInfo);
that.setData({
userInfo: userInfo,
hasLogin: true
});
wx.showToast({
title: '綁定手機號碼成功',
icon: 'success',
duration: 2000
});
}
});
},
exitLogin: function () {
wx.showModal({
title: '',
confirmColor: '#b4282d',
content: '退出登錄?',
success: function (res) {
if (!res.confirm) {
return;
}
util.request(api.AuthLogout, {}, 'POST');
app.globalData.hasLogin = false;
wx.removeStorageSync('token');
wx.removeStorageSync('userInfo');
wx.reLaunch({
url: '/pages/index/index'
});
}
})
}
})
WXML代碼
<!--pages/ucenter/user/user.wxml-->
<form bindsubmit="formSubmit">
<view class='personal-data'>
<view class='list'>
<view class='item acea-row row-between-wrapper'>
<view>頭像</view>
<view class='pictrue'>
<image src='{{userInfo.avatarUrl}}'></image>
</view>
</view>
<view class='item acea-row row-between-wrapper'>
<view>名字</view>
<view class='input'><input type='text' disabled='true' name='nickname' value='{{userInfo.nickName}}'></input></view>
</view>
<view class='item acea-row row-between-wrapper'>
<view>手機號碼</view>
<button name='phone' class='phoneW' value='{{userInfo.phone}}' wx:if="{{!userInfo.phone}}" bindgetphonenumber="getPhoneNumber" hover-class='none' open-type='getPhoneNumber'>
點擊獲取
</button>
<view class='input acea-row row-between-wrapper' wx:else>
<input type='text' disabled='true' name='phone' value='{{userInfo.phone}}' class='id'></input>
<text class='iconfont icon-suozi'></text>
</view>
</view>
<view class='item acea-row row-between-wrapper'>
<view>ID號</view>
<view class='input acea-row row-between-wrapper'>
<input type='text' value='1000{{userInfo.userId}}' disabled='true' class='id'></input>
<text class='iconfont icon-suozi'></text>
</view>
</view>
</view>
<button class='modifyBnt' bindtap="exitLogin">退 出</button>
</view>
</form>
后端代碼
/**
* 綁定手機號碼
*
* @param userId
* @param body
* @return
*/
@PostMapping("bindPhone")
public Object bindPhone(@LoginUser Integer userId, @RequestBody String body) {
log.info("【請求開始】綁定手機號碼,請求參數(shù),body:{}", body);
String sessionKey = UserTokenManager.getSessionKey(userId);
String encryptedData = JacksonUtil.parseString(body, "encryptedData");
String iv = JacksonUtil.parseString(body, "iv");
WxMaPhoneNumberInfo phoneNumberInfo = null;
try {
phoneNumberInfo = this.wxService.getUserService().getPhoneNoInfo(sessionKey, encryptedData, iv);
} catch (Exception e) {
log.error("綁定手機號碼失敗,獲取微信綁定的手機號碼出錯:{}", body);
e.printStackTrace();
return ResponseUtil.fail();
}
String phone = phoneNumberInfo.getPhoneNumber();
WxUser user = userService.selectByPrimaryKey(userId);
user.setMobile(phone);
if (userService.updateById(user) == 0) {
log.error("綁定手機號碼,更新用戶信息出錯,id:{}", user.getId());
return ResponseUtil.updatedDataFailed();
}
Map<Object, Object> data = new HashMap<Object, Object>();
data.put("phone", phone);
log.info("【請求結束】綁定手機號碼,響應結果:{}", JSONObject.toJSONString(data));
return ResponseUtil.ok(data);
}
效果展示
四、注銷登錄
注銷登錄的前端代碼同上,后端代碼如下:
后端代碼
/**
* 注銷登錄
*/
@PostMapping("logout")
public Object logout(@LoginUser Integer userId) {
log.info("【請求開始】注銷登錄,請求參數(shù),userId:{}", userId);
if (userId == null) {
return ResponseUtil.unlogin();
}
try {
UserTokenManager.removeToken(userId);
} catch (Exception e) {
log.error("注銷登錄出錯:userId:{}", userId);
e.printStackTrace();
return ResponseUtil.fail();
}
log.info("【請求結束】注銷登錄成功!");
return ResponseUtil.ok();
}
效果演示
??
到這里我的分享就結束了,歡迎到評論區(qū)探討交流??!
??如果覺得有用的話還請點個贊吧 ??文章來源:http://www.zghlxwxcb.cn/news/detail-719433.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-719433.html
到了這里,關于微信小程序三種授權登錄以及授權登錄流程講解的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!