1. 前言
- 登录很简单,基本都做过,但是进行总结的可能不多
- 今天闲来无事就总结一波
2. 登录方式
- 微信小程序的登录流程分为两种情况
- 一种是使用微信开放平台登录
- 一种是使用自定义登录方式
3. 使用微信开放平台登录
- 用户在小程序中点击
登录
按钮,触发登录事件。- 小程序调用
wx.login()
方法获取临时登录凭证
code。- 小程序调用
wx.getUserInfo()
方法获取用户的基本信息
(头像、昵称等)。- 小程序将
code
和用户信息发送给开发者的后台服务器
。- 开发者的后台服务器使用
AppID
和AppSecret
调用微信接口获取 session_key 和 openid
。- 开发者的后台服务器使用
session_key
对用户信息进行解密,获取用户的真实信息。- 开发者的后台服务器将用户的信息存储到数据库中,并生成一个自定义登录态
token
并返回给小程序。- 小程序
保存
该自定义登录态token
,并在以后的请求
中带上该token
。
4. 相关代码
- 客户端授权登录
// 点击按钮触发登录事件 wx.login({ success: res => { // 获取临时登录凭证 const code = res.code; // 获取用户信息 wx.getUserInfo({ success: res => { const userInfo = res.userInfo; // 将 code 和 userInfo 发送给后台服务器 wx.request({ url: 'https://xx.xx.com/api/login', data: { code: code, userInfo: userInfo }, success: res => { // 将服务器返回的自定义登录态 token 存储到本地 wx.setStorageSync('token', res.data.token); } }); } }); } });
- 后台服务器处理登录逻辑
const request = require('request'); const crypto = require('crypto'); const APP_ID = '你的 app id'; const APP_SECRET = '你的 app secret'; // 处理小程序端登录请求 function login(req, res) { const code = req.body.code; const userInfo = req.body.userInfo; // 获取 session_key 和 openid request(`https://api.weixin.qq.com/sns/jscode2session?appid=${APP_ID}&secret=${APP_SECRET}&js_code=${code}&grant_type=authorization_code`, function(error, response, body) { const result = JSON.parse(body); const session_key = result.session_key; const openid = result.openid; // 使用 session_key 对用户信息进行解密 const encryptedData = userInfo.encryptedData; const iv = userInfo.iv; const decipher = crypto.createDecipheriv('aes-128-cbc', new Buffer(session_key, 'base64'), new Buffer(iv, 'base64')); let decoded = decipher.update(encryptedData, 'base64', 'utf8'); decoded += decipher.final('utf8'); const userInfoObj = JSON.parse(decoded); // 将用户信息存储到数据库中,生成自定义登录态 token 并返回 const token = generateToken(userInfoObj); res.json({ token: token }); }); } // 生成自定义登录态 token function generateToken(userInfo) { const secret = 'your secret key'; const expireTime = new Date().getTime() + 24 * 3600 * 1000; const data = JSON.stringify({ userInfo: userInfo, expireTime: expireTime }); const hash = crypto.createHmac('sha256', secret).update(data).digest('hex'); const token = `${data}.${hash}`; return token; }
只是大概流程 没有考虑用户退出登录、token 过期等其他情况的处理。
5. 自定义登录方式
- 用户在小程序中输入
账号密码
,点击“登录”按钮,触发登录事件。- 小程序将用户输入的账号密码
发送
给开发者的后台
服务器。- 开发者的
后台
服务器根据账号密码验证用户的身份,并生成一个自定义登录态token
并返回给小程序。- 小程序保存该自定义登录态 token,并在以后的
请求
中带上该token
。- 需要注意的是,在使用自定义登录方式时,为了保障用户数据的安全,需要使用 HTTPS 协议,并对用户密码进行加密传输和存储
6. 相关代码
- 客户端登录逻辑
// 自定义登录函数,使用用户名和密码登录 const login = (username, password) => { return new Promise((resolve, reject) => { wx.request({ url: 'https://xx.yzs.com/api/login', method: 'POST', data: { username: username, password: password }, success: res => { // 将服务器返回的自定义登录态 token 存储到本地 wx.setStorageSync('token', res.data.token); resolve(res.data); }, fail: err => { reject(err); } }); }); }; // 在登录页面中调用 login 函数进行登录 const handleLogin = () => { const username = '密码'; const password = '用户名'; login(username, password).then(res => { // 登录成功,跳转到首页 wx.redirectTo({ url: '/pages/home/index', }); }).catch(err => { // 登录失败,提示错误信息 wx.showToast({ title: '登录失败,请重试!', icon: 'none' }); }); };
- 后台相关逻辑
const express = require('express'); const app = express(); const bodyParser = require('body-parser'); const crypto = require('crypto'); app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json()); // 处理自定义登录请求 app.post('/api/login', (req, res) => { const username = req.body.username; const password = req.body.password; // 根据用户名和密码查询用户信息 const user = getUserByUsernameAndPassword(username, password); if (!user) { res.status(401).json({ message: '用户名或密码错误!' }); return; } // 将用户信息存储到数据库中,生成自定义登录态 token 并返回 const token = generateToken(user); res.json({ token: token }); }); // 生成自定义登录态 token const generateToken = user => { const secret = '自己的secret key'; const expireTime = new Date().getTime() + 24 * 3600 * 1000; const data = JSON.stringify({ userId: user.id, expireTime: expireTime }); const hash = crypto.createHmac('sha256', secret).update(data).digest('hex'); const token = `${data}.${hash}`; return token; }; // 根据用户名和密码查询用户信息 const getUserByUsernameAndPassword = (username, password) => { // TODO: 实现根据用户名和密码查询用户信息的逻辑 return { id: 123, username: 'testuser', nickname: 'Test User' }; }; app.listen(3000, () => { console.log('Server started on port 3000.'); });
7. 请求配置 token
- 核心代码
// 假设 token 存在于本地缓存中,缓存的键名为 'token' const token = wx.getStorageSync('token') wx.request({ url: 'https://xx.com/api/some-resource', header: { 'Authorization': `Bearer ${token}` }, success(res) { console.log(res.data) }, fail(err) { console.error(err) } })
- 通过
wx.getStorageSync()
方法获取本地缓存中存储的 token,- 然后将其添加到
header
对象中的 Authorization 属性中,值为 Bearer ${token},- 其中 Bearer 为固定字符串,
${token}
是变量,表示真正的 token 值。- 最终发送的请求头会包含
Authorization: Bearer ${token}
,其中 ${token} 会被替换为真实的 token 值。