微信小程序接口调用:如何确保登录状态下才能访问
微信小程序开发中,部分接口涉及用户隐私数据或业务核心逻辑,必须要求用户处于登录状态才能访问。如果未做登录校验,可能导致数据泄露、业务逻辑异常等问题。本文将介绍几种常用的校验方案,帮助开发者实现登录态校验逻辑。
一、核心思路:登录态的存储与校验
微信小程序的登录态通常基于wx.login接口获取的用户临时凭证code,配合后端服务生成自定义登录态(如Token),存储在本地后随请求携带,后端校验Token有效性后返回对应数据。整个流程的核心环节包括:登录态生成、本地存储、请求携带、后端校验。
二、具体实现步骤
1. 前端登录并存储登录态
首先在小程序启动时或用户触发登录操作时,调用wx.login获取临时code,发送给后端换取自定义Token,再将Token存储到本地缓存中。
// 小程序端登录逻辑
wx.login({
success: (res) => {
if (res.code) {
// 将code发送给后端换取Token
wx.request({
url: 'https://www.ipipp.com/api/login',
method: 'POST',
data: {
code: res.code
},
success: (loginRes) => {
const token = loginRes.data.token;
if (token) {
// 存储Token到本地缓存,过期时间可自定义
wx.setStorageSync('userToken', token);
wx.setStorageSync('tokenExpire', Date.now() + 2 * 60 * 60 * 1000); // 假设2小时过期
}
}
})
} else {
console.log('登录失败!' + res.errMsg)
}
}
})2. 封装请求拦截器,自动携带登录态
为了避免每个请求都手动添加Token,我们可以封装一个统一的请求方法,在请求头中自动携带存储的Token,同时处理Token过期的情况。
// 封装请求方法
function request(url, method, data) {
return new Promise((resolve, reject) => {
// 获取本地存储的Token
const token = wx.getStorageSync('userToken');
const tokenExpire = wx.getStorageSync('tokenExpire');
// 判断Token是否过期
if (!token || Date.now() > tokenExpire) {
// Token不存在或已过期,跳转登录页或重新登录
wx.navigateTo({
url: '/pages/login/login'
})
reject(new Error('登录态已过期,请重新登录'))
return;
}
wx.request({
url: url,
method: method,
data: data,
header: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}` // 携带Token到请求头
},
success: (res) => {
if (res.statusCode === 401) {
// 后端返回未授权,说明Token无效,清除本地存储并跳转登录
wx.removeStorageSync('userToken');
wx.removeStorageSync('tokenExpire');
wx.navigateTo({
url: '/pages/login/login'
})
reject(new Error('登录态无效,请重新登录'))
return;
}
resolve(res.data)
},
fail: (err) => {
reject(err)
}
})
})
}
// 使用示例
request('https://www.ipipp.com/api/user/info', 'GET').then(res => {
console.log('用户信息:', res)
}).catch(err => {
console.log('请求失败:', err)
})3. 后端校验登录态
后端接收到请求后,从请求头中取出Token,校验其有效性(是否过期、是否被篡改等),校验通过才返回对应数据,否则返回401状态码。
以Node.js + Express为例,后端校验逻辑如下:
const express = require('express');
const jwt = require('jsonwebtoken');
const app = express();
app.use(express.json());
// 密钥,实际项目中请妥善保管,不要硬编码在前端或公开代码中
const JWT_SECRET = 'your_jwt_secret_key';
// 登录接口,换取Token
app.post('/api/login', (req, res) => {
const { code } = req.body;
// 这里省略调用微信接口校验code、获取用户openid等逻辑
// 假设校验通过后生成Token
const token = jwt.sign(
{ userId: '123456', openid: 'user_openid' },
JWT_SECRET,
{ expiresIn: '2h' } // Token有效期2小时
);
res.json({ token })
})
// 登录态校验中间件
const authMiddleware = (req, res, next) => {
const authHeader = req.headers.authorization;
if (!authHeader) {
return res.status(401).json({ msg: '未携带登录凭证' })
}
const token = authHeader.split(' ')[1];
try {
const decoded = jwt.verify(token, JWT_SECRET);
req.user = decoded; // 将解析出的用户信息挂载到req上,后续接口可直接使用
next();
} catch (err) {
return res.status(401).json({ msg: '登录态无效或已过期' })
}
}
// 需要登录才能访问的接口
app.get('/api/user/info', authMiddleware, (req, res) => {
// 这里可以通过req.user获取用户ID等信息,查询对应用户数据
res.json({ userId: req.user.userId, name: '测试用户', age: 20 })
})
app.listen(3000, () => {
console.log('服务启动在3000端口')
})三、额外校验方案:结合接口权限配置
如果小程序中部分页面或接口属于公开访问,部分需要登录,可以在小程序全局配置或页面配置中标记接口是否需要登录,请求时统一判断。
// 接口权限配置表
const apiAuthConfig = {
'https://www.ipipp.com/api/user/info': true, // 需要登录
'https://www.ipipp.com/api/public/list': false // 不需要登录
}
function request(url, method, data) {
return new Promise((resolve, reject) => {
// 如果该接口需要登录,先校验登录态
if (apiAuthConfig[url]) {
const token = wx.getStorageSync('userToken');
const tokenExpire = wx.getStorageSync('tokenExpire');
if (!token || Date.now() > tokenExpire) {
wx.navigateTo({ url: '/pages/login/login' })
reject(new Error('请先登录'))
return;
}
}
// 后续请求逻辑同上
})
}四、注意事项
Token的存储建议使用
wx.setStorageSync,不要存储在全局变量中,避免小程序销毁后丢失。Token过期后,除了跳转登录页,也可以实现无感刷新Token的逻辑:后端返回过期时,前端用旧的refresh_token换取新Token,避免用户重复操作。
后端校验时,JWT密钥等敏感信息不要暴露在前端代码中,所有涉及用户身份校验的逻辑都放在服务端处理。
对于高安全性要求的接口,可以增加请求签名、时间戳校验等额外逻辑,防止请求被篡改或重放攻击。
总结:确保微信小程序接口在登录状态下访问的核心,是前端存储有效登录态并在请求中携带,后端对登录态进行校验,两者配合实现完整的权限控制逻辑。