目錄
一、流程講解
1. 圖解
2. 講解
二、官方登入
wxLogin
wx.getUserProfile
代碼
三、數(shù)據(jù)交互授權(quán)登入
1. 前端
2. 后端代碼
一、流程講解
1. 圖解
2. 講解
這張圖片是關(guān)于微信小程序授權(quán)登錄的流程圖。流程圖展示了使用微信官方提供的登錄能力來(lái)獲取用戶身份標(biāo)識(shí)的過(guò)程。下面是對(duì)流程圖中的一些關(guān)鍵步驟的解釋:
1. 小程序通過(guò)微信官方提供的登錄能力獲取微信提供的用戶身份標(biāo)識(shí),以便在小程序內(nèi)建立用戶體系。
2. 開(kāi)發(fā)者需要在小程序中調(diào)用wx.login()方法來(lái)獲取一個(gè)臨時(shí)的code,該code是一個(gè)臨時(shí)的字符串,再通過(guò)wx.request()?發(fā)起網(wǎng)絡(luò)請(qǐng)求,將 code 傳給后臺(tái)服務(wù)端。
3. 開(kāi)發(fā)者服務(wù)器通過(guò)發(fā)送code及AppID(小程序ID)和AppSecret(小程序密鑰)[ 后面發(fā)送的ID對(duì)于微信接口服務(wù)來(lái)說(shuō)是唯一標(biāo)識(shí) ]調(diào)用微信接口服務(wù)(Wechat Http Api),以獲取session_key和openid等信息。session_key指的是當(dāng)前的登錄請(qǐng)求,是一次會(huì)話的標(biāo)識(shí)。
4. 開(kāi)發(fā)者服務(wù)器將session_key和openid ( 微信接口轉(zhuǎn)過(guò)來(lái)的openid對(duì)于3微信小程序來(lái)說(shuō)是授權(quán)的唯一標(biāo)識(shí) )?等用戶信息與自定義登錄態(tài)關(guān)聯(lián)起來(lái),返回自定義登錄態(tài)給小程序。
5. 小程序在后續(xù)的業(yè)務(wù)請(qǐng)求中,可以攜帶自定義登錄態(tài)來(lái)向開(kāi)發(fā)者服務(wù)器發(fā)起請(qǐng)求,以獲取業(yè)務(wù)數(shù)據(jù)。
6. 開(kāi)發(fā)者服務(wù)器通過(guò)驗(yàn)證自定義登錄態(tài),返回相應(yīng)的業(yè)務(wù)數(shù)據(jù)給小程序。
總的來(lái)說(shuō),微信小程序授權(quán)登錄的流程包括小程序端調(diào)用wx.login()方法獲取臨時(shí)code,開(kāi)發(fā)者服務(wù)器通過(guò)code+AppID+AppSecret獲取session_key和openid等信息,并將其與自定義登錄態(tài)關(guān)聯(lián)起來(lái),最后小程序可以使用自定義登錄態(tài)來(lái)向開(kāi)發(fā)者服務(wù)器發(fā)起業(yè)務(wù)請(qǐng)求。
二、官方登入
在官方文檔中,有通過(guò)授權(quán)登入的方法及代碼,我這里將其復(fù)制到項(xiàng)目中,進(jìn)行一個(gè)演示。
其中有兩個(gè)方法,有分別不同的用戶體驗(yàn)及安全問(wèn)題。以下就給大家演示:
-
wxLogin
調(diào)用接口獲取登錄憑證(code)。通過(guò)憑證進(jìn)而換取用戶登錄態(tài)信息,包括用戶在當(dāng)前小程序的唯一標(biāo)識(shí)(openid)、微信開(kāi)放平臺(tái)賬號(hào)下的唯一標(biāo)識(shí)(unionid,若當(dāng)前小程序已綁定到微信開(kāi)放平臺(tái)賬號(hào))及本次登錄的會(huì)話密鑰(session_key)等。用戶數(shù)據(jù)的加解密通訊需要依賴會(huì)話密鑰完成。
參數(shù)了解 :
屬性 | 類型 | 默認(rèn)值 | 必填 | 說(shuō)明 | 最低版本 |
---|---|---|---|---|---|
timeout | number | 否 | 超時(shí)時(shí)間,單位ms | 1.9.90 | |
success | function | 否 | 接口調(diào)用成功的回調(diào)函數(shù) | ||
fail | function | 否 | 接口調(diào)用失敗的回調(diào)函數(shù) | ||
complete | function | 否 | 接口調(diào)用結(jié)束的回調(diào)函數(shù)(調(diào)用成功、失敗都會(huì)執(zhí)行) |
code | string | 用戶登錄憑證(有效期五分鐘)。開(kāi)發(fā)者需要在開(kāi)發(fā)者服務(wù)器后臺(tái)調(diào)用?code2Session,使用 code 換取 openid、unionid、session_key 等信息 |
演示效果 :?
由操作可看出,該方法對(duì)于用戶的體驗(yàn)及安全性問(wèn)題有所欠缺,點(diǎn)擊就直接獲取到了用戶的信息,進(jìn)行了一個(gè)顯示,這個(gè)方法官方已經(jīng)不推薦了。
-
wx.getUserProfile
獲取用戶信息。頁(yè)面產(chǎn)生點(diǎn)擊事件(例如?
button
?上?bindtap
?的回調(diào)中)后才可調(diào)用,每次請(qǐng)求都會(huì)彈出授權(quán)窗口,用戶同意后返回?userInfo
。該接口用于替換?wx.getUserInfo
,詳見(jiàn)?用戶信息接口調(diào)整說(shuō)明。
參數(shù)了解 :
屬性 | 類型 | 默認(rèn)值 | 必填 | 說(shuō)明? | ||
---|---|---|---|---|---|---|
lang | string | en | 否 | 顯示用戶信息的語(yǔ)言 | ||
desc | string | 是 | 聲明獲取用戶個(gè)人信息后的用途,不超過(guò)30個(gè)字符 | |||
success | function | 否 | 接口調(diào)用成功的回調(diào)函數(shù) | |||
fail | function | 否 |
|
|||
complete | function | 否 | 接口調(diào)用結(jié)束的回調(diào)函數(shù)(調(diào)用成功、失敗都會(huì)執(zhí)行) |
演示效果 :?
相比之下,該方法要更有用戶體驗(yàn)及提高安全問(wèn)題。
信息了解 :
用戶信息接口調(diào)整說(shuō)明https://developers.weixin.qq.com/community/develop/doc/000cacfa20ce88df04cb468bc52801?highLine=login
-
代碼
index.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>
index.js
// pages/index/index.js
Page({
data: {
userInfo: {},
canIUseGetUserProfile: true,
},
onLoad() {
// if (wx.getUserProfile) {
// this.setData({
// canIUseGetUserProfile: true
// })
// }
},
getUserProfile(e) {
console.log('getUserProfile')
// 推薦使用 wx.getUserProfile 獲取用戶信息,開(kāi)發(fā)者每次通過(guò)該接口獲取用戶個(gè)人信息均需用戶確認(rèn)
// 開(kāi)發(fā)者妥善保管用戶快速填寫(xiě)的頭像昵稱,避免重復(fù)彈窗
wx.getUserProfile({
desc: '用于完善會(huì)員資料', // 聲明獲取用戶個(gè)人信息后的用途,后續(xù)會(huì)展示在彈窗中,請(qǐng)謹(jǐn)慎填寫(xiě)
success: (res) => {
console.log(res);
this.setData({
userInfo: res.userInfo,
hasUserInfo: true
})
}
})
},
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;
}
},
/**
* 生命周期函數(shù)--監(jiān)聽(tīng)頁(yè)面初次渲染完成
*/
onReady() {
},
/**
* 生命周期函數(shù)--監(jiān)聽(tīng)頁(yè)面顯示
*/
onShow() {
},
/**
* 生命周期函數(shù)--監(jiān)聽(tīng)頁(yè)面隱藏
*/
onHide() {
},
/**
* 生命周期函數(shù)--監(jiān)聽(tīng)頁(yè)面卸載
*/
onUnload() {
},
/**
* 頁(yè)面相關(guān)事件處理函數(shù)--監(jiān)聽(tīng)用戶下拉動(dòng)作
*/
onPullDownRefresh() {
},
/**
* 頁(yè)面上拉觸底事件的處理函數(shù)
*/
onReachBottom() {
},
/**
* 用戶點(diǎn)擊右上角分享
*/
onShareAppMessage() {
}
})
js文件中?canIUseGetUserProfile 屬性值為 : true時(shí),就是wx.getUserProfile方法,當(dāng)為false,就是wxLogin方法。
三、數(shù)據(jù)交互授權(quán)登入
以下代碼是基于我博客中進(jìn)行的續(xù)寫(xiě) :?微信小程序開(kāi)發(fā)之后臺(tái)數(shù)據(jù)交互及wxs應(yīng)用
1. 前端
在項(xiàng)目中編寫(xiě) api.js 文件中的請(qǐng)求訪問(wèn)地址
// 以下是業(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)
};
注意 :? ?需要對(duì)應(yīng)后臺(tái)的請(qǐng)求地址之后進(jìn)行數(shù)據(jù)的訪問(wèn)。
個(gè)人中心
在個(gè)人中心頁(yè)面的 index.wxml 文件中進(jìn)行編寫(xiě):
<view class="page-container">
<view class="user-info-container">
<view class="user-info" bindtap="goLogin">
<image class="user-img" mode="scaleToFill" src="{{userInfo.avatarUrl}}" />
<text class="user-info-name">{{userInfo.nickName}}</text>
</view>
<image class="user-update" src="/static/tabBar/component.png" bindtap='goPages' data-url='/pages/ucenter/user/user'/>
</view>
<view class="boundary" />
<view class="cells-container">
<view class="cell-wrap">
<image class="cell-icon" src="/static/tabBar/sdk.png" />
<text class="cell-text">我主持的會(huì)議</text>
<view class="cell-right">
<view class="cell-list-num">{{metting_pubs}}</view>
<view class="cell-arrow"></view>
</view>
</view>
<view class="cell-wrap">
<image class="cell-icon" src="/static/tabBar/sdk.png" />
<text class="cell-text">我參與的會(huì)議</text>
<view class="cell-right">
<view class="cell-list-num">{{metting_joins}}</view>
<view class="cell-arrow"></view>
</view>
</view>
</view>
<view class="boundary" />
<view class="cells-container">
<view class="cell-wrap">
<image class="cell-icon" src="/static/tabBar/sdk.png" />
<text class="cell-text">我發(fā)布的投票</text>
<view class="cell-right">
<view class="cell-list-num">1</view>
<view class="cell-arrow"></view>
</view>
</view>
<view class="cell-wrap">
<image class="cell-icon" src="/static/tabBar/sdk.png" />
<text class="cell-text">我參與的投票</text>
<view class="cell-right">
<view class="cell-list-num">10</view>
<view class="cell-arrow"></view>
</view>
</view>
</view>
<view class="boundary" />
<view class="cells-container">
<view class="cell-wrap">
<image class="cell-icon" src="/static/tabBar/template.png" />
<text class="cell-text">消息</text>
<view class="cell-right">
<view class="cell-list-num"></view>
<view class="cell-arrow"></view>
</view>
</view>
<view class="cell-wrap">
<image class="cell-icon" src="/static/tabBar/component.png" />
<text class="cell-text">設(shè)置</text>
<view class="cell-right">
<view class="cell-list-num"></view>
<view class="cell-arrow"></view>
</view>
</view>
</view>
</view>
在 index.js 中編寫(xiě)數(shù)據(jù)請(qǐng)求及方法
// pages/ucenter/index/index.js
var util = require('../../../utils/util.js');
var api = require('../../../config/api.js');
const app = getApp();
Page({
/**
* 頁(yè)面的初始數(shù)據(jù)
*/
data: {
userInfo: {
nickName: '點(diǎn)擊登錄',
avatarUrl: '/static/images/avatar.png'
},
hasLogin: false,
metting_pubs: '',
metting_joins: ''
},
/**
* 生命周期函數(shù)--監(jiān)聽(tīng)頁(yè)面加載
*/
onLoad(options) {
},
/**
* 生命周期函數(shù)--監(jiān)聽(tīng)頁(yè)面顯示
*/
onShow() {
this.getUserInfo();
},
getUserInfo() {
// console.log('ucenter.index.app.globalData.hasLogin='+app.globalData.hasLogin)
//獲取用戶的登錄信息
if (app.globalData.hasLogin) {
let userInfo = wx.getStorageSync('userInfo');
this.setData({
userInfo: userInfo,
hasLogin: true
});
//查詢個(gè)人統(tǒng)計(jì)信息
util.request(api.UserIndex).then(res => {
if (res.errno === 0) {
this.setData({
metting_pubs: res.data.metting_pubs,
metting_joins: res.data.metting_joins
});
}
});
}
},
goLogin() {
if (!this.data.hasLogin) {
wx.navigateTo({
url: "/pages/auth/login/login"
});
}
},
/**
* 頁(yè)面跳轉(zhuǎn)
*/
goPages: function (e) {
if (this.data.hasLogin) {
wx.navigateTo({
url: e.currentTarget.dataset.url
});
} else {
wx.navigateTo({
url: "/pages/auth/login/login"
});
};
}
})
創(chuàng)建一個(gè)用戶登入后的設(shè)置頁(yè)面為 : user
user.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>手機(jī)號(hào)碼</view>
<button name='phone' class='phoneW' value='{{userInfo.phone}}' wx:if="{{!userInfo.phone}}" bindgetphonenumber="getPhoneNumber" hover-class='none' open-type='getPhoneNumber'>
點(diǎn)擊獲取
</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號(hào)</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>
user.wxss
@import '/static/font/iconfont.wxss';
.personal-data .list {
margin-top: 15rpx;
background-color: #fff;
}
.personal-data .list .item {
padding: 30rpx 30rpx 30rpx 0;
border-bottom: 1rpx solid #f2f2f2;
margin-left: 30rpx;
font-size: 32rpx;
color: #282828;
}
.personal-data .list .item .phone {
background-color: #85c43f;
width: 160rpx;
height: 56rpx;
font-size: 24rpx;
color: #fff;
line-height: 56rpx;
border-radius: 32rpx
}
.personal-data .list .item .pictrue {
width: 88rpx;
height: 88rpx;
}
.personal-data .list .item .pictrue image {
width: 100%;
height: 100%;
border-radius: 50%;
}
.personal-data .list .item .input {
width: 415rpx;
text-align: right;
color: #868686;
}
.personal-data .list .item .input .id {
width: 365rpx;
}
.personal-data .list .item .input .iconfont {
font-size: 35rpx;
}
.personal-data .modifyBnt {
/* background-color: #85c43f; */
/* background: linear-gradient(to left right, #85c43f, #fefefd); */
background: radial-gradient(circle at 50%,#85c43f,#CDDC39);
font-size: 32rpx;
color: #fff;
width: 690rpx;
height: 90rpx;
border-radius: 50rpx;
display: flex;
justify-content: center;
align-items: center;
line-height: 90rpx;
margin: 76rpx auto 0 auto;
}
.acea-row{display:flex;flex-wrap:wrap;}
.acea-row.row-top{align-items:flex-start;}
.acea-row.row-middle{align-items:center;}
.acea-row.row-bottom{align-items:flex-end;}
.acea-row.row-left{justify-content:flex-start;}
.acea-row.row-center{justify-content:center;}
.acea-row.row-right{justify-content:flex-end;}
.acea-row.row-between{justify-content:space-between;}
.acea-row.row-around{justify-content:space-around;}
.acea-row.row-column{flex-direction:column;}
.acea-row.row-column-between{flex-direction:column;justify-content:space-between;}
.acea-row.row-column-around{flex-direction:column;justify-content:space-around;}
.acea-row.row-center-wrapper{align-items:center;justify-content:center;}
.acea-row.row-between-wrapper{align-items:center;justify-content:space-between;}
view, image, text, navigator {
box-sizing: border-box;
padding: 0;
margin: 0;
}
user.js
var util = require('../../../utils/util.js');
var api = require('../../../config/api.js');
var user = require('../../../utils/user.js');
var app = getApp();
Page({
/**
* 頁(yè)面的初始數(shù)據(jù)
*/
data: {
userInfo: {},
hasLogin: false,
userSharedUrl: ''
},
/**
* 生命周期函數(shù)--監(jiān)聽(tīng)頁(yè)面加載
*/
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") {
// 拒絕授權(quán)
return;
}
if (!this.data.hasLogin) {
wx.showToast({
title: '綁定失?。赫?qǐng)先登錄',
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;//設(shè)置手機(jī)號(hào)碼
wx.setStorageSync('userInfo', userInfo);
that.setData({
userInfo: userInfo,
hasLogin: true
});
wx.showToast({
title: '綁定手機(jī)號(hào)碼成功',
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'
});
}
})
}
})
2. 后端代碼
在后臺(tái)編寫(xiě)的控制器,來(lái)進(jìn)行出來(lái)前端的請(qǐng)求及數(shù)據(jù)處理并且反饋帶前端
WxAuthController :?
package com.CloudJun.ssm.wxcontroller;
/**
* @Autho donkee
* @Since 2022/6/27
*/
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import com.alibaba.fastjson.JSONObject;
import com.CloudJun.ssm.annotation.LoginUser;
import com.CloudJun.ssm.model.UserInfo;
import com.CloudJun.ssm.model.WxLoginInfo;
import com.CloudJun.ssm.model.WxUser;
import com.CloudJun.ssm.service.UserToken;
import com.CloudJun.ssm.service.UserTokenManager;
import com.CloudJun.ssm.service.WxUserService;
import com.CloudJun.ssm.util.JacksonUtil;
import com.CloudJun.ssm.util.ResponseUtil;
import com.CloudJun.ssm.util.UserTypeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import javax.servlet.http.HttpServletRequest;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* 鑒權(quán)服務(wù)
*/
@Slf4j
@RestController
@RequestMapping("/wx/auth")
public class WxAuthController {
@Autowired
private WxMaService wxService;
@Autowired
private WxUserService userService;
/**
* 微信登錄
*
* @param wxLoginInfo
* 請(qǐng)求內(nèi)容,{ code: xxx, userInfo: xxx }
* @param request
* 請(qǐng)求對(duì)象
* @return 登錄結(jié)果
*/
@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);
}
/**
* 綁定手機(jī)號(hào)碼
*
* @param userId
* @param body
* @return
*/
@PostMapping("bindPhone")
public Object bindPhone(@LoginUser Integer userId, @RequestBody String body) {
log.info("【請(qǐng)求開(kāi)始】綁定手機(jī)號(hào)碼,請(qǐng)求參數(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("綁定手機(jī)號(hào)碼失敗,獲取微信綁定的手機(jī)號(hào)碼出錯(cuò):{}", 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("綁定手機(jī)號(hào)碼,更新用戶信息出錯(cuò),id:{}", user.getId());
return ResponseUtil.updatedDataFailed();
}
Map<Object, Object> data = new HashMap<Object, Object>();
data.put("phone", phone);
log.info("【請(qǐng)求結(jié)束】綁定手機(jī)號(hào)碼,響應(yīng)結(jié)果:{}", JSONObject.toJSONString(data));
return ResponseUtil.ok(data);
}
/**
* 注銷登錄
*/
@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();
}
}
在 application.yml 文件中進(jìn)行配置后臺(tái)的數(shù)據(jù)庫(kù)及微信小程序的AppID(小程序ID)及AppSecret(小程序密鑰),來(lái)幫助訪問(wèn)微信的接口服務(wù)。
server:
port: 8080 #指服器端口號(hào)
servlet:
context-path: /oapro
spring:
datasource:
#type連接池類型 DBCP,C3P0,Hikari,Druid,默認(rèn)為Hikari
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis_oapro?useUnicode=true&characterEncoding=UTF-8&useSSL=false
username: root
password: 123456
mybatis:
mapper-locations: classpath*:mapper/*.xml #指定mapper文件位置
type-aliases-package: com.CloudJun.ssm.model #指定自動(dòng)生成別名所在包
logging:
level:
root: info
org.springframework: info
org.mybatis: ERROR
com.CloudJun.ssm.mapper: debug
oa:
wx:
app-id: # 這里填寫(xiě)AppID(小程序ID)
app-secret: # 這里填寫(xiě)AppSecret(小程序密鑰)
msgDataFormat: JSON
最后后臺(tái)開(kāi)啟服務(wù),在前端進(jìn)行數(shù)據(jù)訪問(wèn)及微信授權(quán)登入
后臺(tái)的服務(wù)開(kāi)起后,可以在模擬器中可以看到的效果 :?文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-752972.html
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-752972.html
到了這里,關(guān)于微信小程序之微信授權(quán)登入及授權(quán)的流程講解的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!