微信小程序-实现微信授权自动登录功能
显示效果
授权前界面
授权弹框界面
采用了wx.getUserProfile API申请用户信息,若基础库版本过高,例如3.7.7,则不会显示弹窗,默认为允许状态。

若基础库版本降低,例如2.25.4,则会显示弹窗,如下图所示


授权后界面

前端部分
基础封装
新建utils文件夹,在该文件夹下新建login.js文件,在该文件中编写以下内容
/**
* 检测用户是否登陆
*/
export function checkLogin(){
return new Promise(function(resolve,reject){
if(wx.getStorageSync('userInfo') && wx.getStorageSync('token')){
checkSession().then(()=>{
resolve(true);
}).catch(()=>{
reject(false);
})
}else{
reject(false);
}
})
}
/**
* 调用wx.checkSession()检测当前登录状态是否有效
*/
function checkSession(){
return new Promise(function(resolve,reject){
wx.checkSession({
success:function(){
resolve(true);
},
fail:function(){
reject(false);
}
})
})
}
/**
* 调用wx.login() 获取用户临时登录凭证code
*/
export function wxlogin(){
return new Promise(function(resolve,reject){
wx.login({
success: (res) => {
if(res.code){
resolve(res);
}else{
reject(res);
}
},
fail:function(error){
reject(error);
}
})
})
}
在api文件夹下新增auth.js文件,并编写以下内容
import {wxlogin} from '../../utils/login'
const app = getApp();
export function loginByWeixinShouQuan(userInfo){
return new Promise(function(resolve,reject){
wxlogin().then((res)=>{
app.wxRequest("/api/weixinopen/wxlogin", "POST", {
code: res.code, //临时授权凭证
userInfo: userInfo, //用户信息
}).then(res => {
if (res.code === 200) {
//存储用户信息
wx.setStorageSync('userInfo', res.data.userInfo);
wx.setStorageSync('token', res.data.token);
resolve(res);
}else{
reject(res);
}
}).catch((error) => {
reject(error);
});
}).catch((error) => {
reject(error);
})
})
}
注意:可以将userInfo对象作为参数发送给用户服务器后台,因为userInfo对象里面包含用户的昵称和头像等信息,但也可以改为将encryptData和iv作为参数发送给用户服务器后台,例如这样,将encryptedData和iv作为loginByWeixinShouQuan的参数,调用用户服务器的时候再传过去,用户服务器后台可以通过其它办法拿到用户的个人信息,例如昵称,头像等,这个稍后再说
import {wxlogin} from '../../utils/login'
const app = getApp();
export function loginByWeixinShouQuan(encryptedData,iv){
return new Promise(function(resolve,reject){
wxlogin().then((res)=>{
app.wxRequest("/api/weixinopen/wxlogin", "POST", {
code: res.code, //临时授权凭证
encryptedData: encryptedData,
iv: iv
}).then(res => {
if (res.code === 200) {
//存储用户信息
wx.setStorageSync('userInfo', res.data.userInfo);
wx.setStorageSync('token', res.data.token);
resolve(res);
}else{
reject(res);
}
}).catch((error) => {
reject(error);
});
}).catch((error) => {
reject(error);
})
})
}
个人中心界面
mine.wxml
<view class='picTxt acea-row row-between-wrapper' bindtap="goLogin">
<view class='pictrue'>
<image src='{{userInfo.avatarUrl}}'></image>
</view>
<view class='text'>
<view class='acea-row row-middle'>
<view class='name line1'>{{userInfo.nickName || '请授权'}}</view>
</view>
<view class='id'>用户编号:{{userInfo.userId || ''}}</view>
</view>
</view>
mine.Js
const app = getApp();
Page({
data: {
userInfo:{
nickName:'点击登录',
avatarUrl:'/resource/image/userhead/avatar.png',
userId:''
},
},
onShow() {
let userInfo = wx.getStorageSync('userInfo');
if(app.globalData.hasLogin || userInfo){
this.setData({
userInfo:userInfo,
});
}
},
goLogin(){
checkLogin().then(()=>{
}).catch((error) => {
console.log('未登录');
wx.navigateTo({
url: "/pages/auth/login/login"
});
})
}
})
登录界面
如下图所示,可以选择微信授权的方式自动登录,也可以选择输入账号密码的方式手动登录

login.wxml
<view class="container">
<view class="login-box">
<button type="primary" class="wx-login-btn" bindtap="getUserProfile">微信授权登录</button>
<button type="primary" class="account-login-btn" bindtap="accountLogin">账号登录</button>
</view>
</view>
login.js
import {
loginByWeixinShouQuan
} from '../../../api/miniapp/auth'
import {showErrorToast} from '../../../utils/util'
import { checkLogin } from '../../../utils/login'
getUserProfile(e){
wx.showLoading({
title: "正在登录...",
mask: true
})
wx.getUserProfile({
desc: '用于完善用户信息',
success:(res)=>{
console.log('wx.getUserProfile返回结果:' + JSON.stringify(res));
if (res.errMsg === 'getUserProfile:ok'){
checkLogin().catch(() => {
loginByWeixinShouQuan(res.userInfo).then(res => {
app.globalData.hasLogin = true;
wx.navigateBack({
delta: 1
})
}).catch((err) => {
app.globalData.hasLogin = false;
showErrorToast('微信登录失败');
wx.hideLoading();
});
})
}else{
app.globalData.hasLogin = false;
showErrorToast('微信登录失败');
wx.hideLoading();
}
},
fail: (res) => {
app.globalData.hasLogin = false;
showErrorToast('微信登录失败');
wx.hideLoading();
}
})
},
解析:
- 通过wx.getUserProfile可以拿到用户信息,用户信息目录结构如下图所示,可以看到userInfo对象里面包含用户的昵称和头像等信息,用户可以将昵称和头像作为参数发送给用户服务器后台,也可以不发,改为将encryptData和iv作为参数发送给用户服务器后台,如果是传encryptData和ivencryptData和iv,则调用时传对应的参数,例如
loginByWeixinShouQuan(res.encryptedData,res.iv)

- showErrorToast是封装的一个函数,函数内容如下
function showErrorToast(msg) {
wx.showToast({
title: msg,
image: '/resource/images/toast/icon_error.png'
})
}
- wx.navigateBack({delta: 1})作用:关闭当前页面,返回上一级页面。
后端部分
- 调用微信接口获取用户登录状态信息
string text = "?appid=" + weixinOpenSettings.AppId + "&secret=" + weixinOpenSettings.AppSecret + "&js_code=" + request.code + "&grant_type=authorization_code";
string requestUri = "https://api.weixin.qq.com/sns/jscode2session" + text;
using HttpClient httpClient = new HttpClient();
byte[] wxresult = httpClient.GetByteArrayAsync(requestUri).Result;
var oiask = JsonConvert.DeserializeObject<OpenIdAndSessionKey>(Encoding.UTF8.GetString(wxresult));
OpenIdAndSessionKey.cs
public class OpenIdAndSessionKey
{
public string openid { get; set; }
public string session_key { get; set; }
public string errcode { get; set; }
public string errmsg { get; set; }
}
解析:<font style="color:rgba(0, 0, 0, 0.85);">https://api.weixin.qq.com/sns/jscode2session</font> 是微信用于获取用户登录状态信息的接口,通过此接口可以拿到openid和session_key信息,需要传入的参数如下
- appid:微信小程序的appid
- secret:微信小程序appid对应的密钥
- js_code:wx.login接口返回的临时登录凭证
- grant_type:固定值authorization_code
注意:若返回errmsg变量值为“invalid code, rid: xxxx”,说明有问题,解决办法参考以下文章
【微信小程序】错误码 40029:invalid code 详解
- 通过传入参数encryptedData、session_key、iv参数调用解密方法获取用户信息(如果接口参数传的是用户信息,则可以直接通过接口参数获取)
if (userFound == null)
{
var user = JsonConvert.DeserializeObject<WeixinAppUserInfo>(Cryptography.AES_decrypt(encryptedData, oiask.session_key, iv)) ?? new WeixinAppUserInfo();
parameters.UserClaim.Nickname = user.nickName;
parameters.UserClaim.HeadImgUrl = user.avatarUrl;
parameters.UserClaim.Sex = user.gender;
parameters.UserClaim.Province = user.province;
parameters.UserClaim.City = user.city;
}
WeixinAppUserInfo.cs
public class WeixinAppUserInfo
{
public class Watermark
{
public string appid { get; set; }
public string timestamp { get; set; }
}
public string openId { get; set; }
public string nickName { get; set; }
public string gender { get; set; }
public string city { get; set; }
public string province { get; set; }
public string country { get; set; }
public string avatarUrl { get; set; }
public string unionId { get; set; }
public Watermark watermark { get; set; }
}
Cryptography.cs
public class Cryptography
{
public static string AES_decrypt(string encryptedData, string Session_key, string IV)
{
try
{
byte[] array = Convert.FromBase64String(encryptedData);
byte[] bytes = new RijndaelManaged
{
Key = Convert.FromBase64String(Session_key),
IV = Convert.FromBase64String(IV),
Mode = CipherMode.CBC,
Padding = PaddingMode.PKCS7
}.CreateDecryptor().TransformFinalBlock(array, 0, array.Length);
return Encoding.Default.GetString(bytes);
}
catch (Exception)
{
return "";
}
}
}
后端返回信息
jwtToken是jwt的token。
WeixinOpenResponseDto data = new WeixinOpenResponseDto()
{
token = jwtToken,
openId = oiask.openid,
userInfo = new UserInfo()
{
userId = userFound.Id.ToString(),
avatarUrl = avatarUrl,
nickName = nickName
}
};
将授权信息存入授权表中。



浙公网安备 33010602011771号