微信小程序授权登录逻辑实现
微信小程序的授权登录是连接用户与后端服务的关键流程。一个健壮、安全的授权逻辑不仅能提升用户体验,也是数据安全的基础。本文将详细介绍其标准实现流程、核心代码、常见陷阱及最佳实践。
1. 核心实现逻辑与代码示例
微信小程序授权登录主要分为前端获取用户凭证、后端验证并建立会话两大步骤。
1.1 前端流程
前端主要负责引导用户授权并获取临时凭证 code。
// pages/login/login.js
Page({
handleLogin: function() {
// 1. 检查用户是否已授权
wx.getSetting({
success: (res) => {
if (res.authSetting['scope.userInfo']) {
// 已授权,直接获取用户信息并登录
this.getUserInfoAndLogin();
} else {
// 未授权,显示授权按钮(由 button 组件触发)
// 或者使用 wx.authorize 提前发起授权(部分 scope 需要)
// 对于 userInfo,通常由 button 触发
}
}
});
},
// 由页面上的 <button open-type="getUserInfo"> 触发
onGetUserInfo: function(e) {
if (e.detail.userInfo) {
// 用户点击了“允许”
const userInfo = e.detail.userInfo;
// 开始登录流程
this.wxLogin();
} else {
// 用户点击了“拒绝”
console.log('用户拒绝了授权');
}
},
wxLogin: function() {
// 2. 调用 wx.login 获取 code
wx.login({
success: (res) => {
if (res.code) {
const code = res.code;
// 3. 将 code 发送到开发者服务器
wx.request({
url: 'https://your-backend.com/api/wx-login',
method: 'POST',
data: { code },
success: (res) => {
if (res.data.success) {
// 登录成功,服务器返回了自定义登录态(如 token)
const token = res.data.token;
// 存储 token 到本地(如 Storage 或 globalData)
wx.setStorageSync('auth_token', token);
// 跳转到首页或进行其他操作
wx.reLaunch({ url: '/pages/index/index' });
}
}
});
} else {
console.log('登录失败!' + res.errMsg);
}
}
});
}
});
1.2 后端流程(Node.js 示例)
后端负责用 code 换取 openid 和 session_key,并建立自己的会话。
// server/controllers/authController.js
const axios = require('axios');
exports.wxLogin = async (req, res) => {
const { code } = req.body;
const appid = 'your-appid';
const secret = 'your-app-secret';
try {
// 1. 使用 code 换取 session_key 和 openid
const url = `https://api.weixin.qq.com/sns/jscode2session?appid=${appid}&secret=${secret}&js_code=${code}&grant_type=authorization_code`;
const response = await axios.get(url);
const { openid, session_key, unionid } = response.data;
if (!openid) {
return res.status(400).json({ success: false, msg: '无效的code' });
}
// 2. (可选) 验证用户信息完整性(如果前端传了 encryptedData 和 iv)
// const { encryptedData, iv } = req.body;
// const decodedUserInfo = decryptData(encryptedData, iv, session_key);
// 3. 根据 openid 查找或创建本地用户
let user = await UserModel.findOne({ openid });
if (!user) {
user = await UserModel.create({ openid, unionid });
}
// 4. 生成自定义登录态(如 JWT Token)
const token = generateJWTToken({ userId: user._id, openid });
// 5. 返回 token 给前端(注意不要返回 session_key)
res.json({ success: true, token });
} catch (error) {
console.error('登录失败:', error);
res.status(500).json({ success: false, msg: '服务器内部错误' });
}
};
// 数据解密函数(示例)
function decryptData(encryptedData, iv, sessionKey) {
// 使用 crypto 模块进行解密,具体实现略
// 返回解密后的用户信息对象
}
2. 常见陷阱
-
混淆
wx.login与wx.getUserInfowx.login用于获取临时凭证code,是登录必需的。wx.getUserInfo(现通常由按钮触发)用于获取用户头像、昵称等身份信息,是可选的。两者目的不同,不应混用。
-
在前端暴露敏感信息
AppSecret必须保存在后端服务器,绝对不能在客户端代码或请求中暴露。session_key是服务器端的会话密钥,用于解密数据,绝不能通过网络传输给前端。
-
未处理用户拒绝授权的情况
- 用户可能拒绝授权
getUserInfo。前端必须有友好的引导和降级处理(例如,使用默认头像和昵称,允许后续再授权)。
- 用户可能拒绝授权
-
code的一次性使用- 一个
code只能使用一次,且有效期很短(约5分钟)。重复使用或过期使用会导致兑换失败。
- 一个
-
会话管理不当
- 仅依赖微信的
openid作为身份标识不够安全。应使用自研的会话机制(如JWT、Session ID),并设置合理的过期时间。 - 忘记将
session_key与用户关联存储,导致后续解密手机号等操作失败。
- 仅依赖微信的
-
未校验数据完整性(如果使用加密数据)
- 当使用
<button open-type="getPhoneNumber">获取加密数据时,必须用session_key和iv在后端解密,并验证数据的完整性,防止伪造。
- 当使用
-
忽略网络请求的失败处理
wx.login、wx.request都可能失败。代码中必须有完整的fail或catch回调,给出用户提示。
3. 总结
实现微信小程序授权登录,关键在于理解其前后端分离的流程:
- 前端:引导授权 -> 获取
code-> 发送code至后端 -> 存储后端返回的自定义登录态。 - 后端:用
code+AppSecret换取openid和session_key-> 创建/查找用户 -> 生成并返回自定义登录态。
牢记以下安全与体验要点:
- 安全第一:
AppSecret和session_key永不泄露给客户端。 - 体验友好:妥善处理用户拒绝授权和网络异常。
- 设计健壮:建立自己的用户体系和会话管理,不依赖微信的临时凭证。
遵循官方文档的最新指引,并充分考虑上述陷阱,即可构建出一个安全、稳定且用户体验良好的小程序登录系统。
如果你在小程序开发、授权登录、前端Bug修复、Node.js接口开发中遇到问题,我可提供专业技术支持,全程闲鱼担保交易,快速解决问题!