当你的接口开始需要「登录态」,你会遇到这些问题:
-
登录后怎么保持用户状态?用 Cookie 还是 Token?
-
Token 要放哪?Header、Cookie、LocalStorage?
-
如何处理鉴权失败、自动过期、权限控制?
-
每个接口都手动判断用户?会不会太麻烦?
别急,这一篇,我们就来一次性讲清楚登录认证体系、Session 管理与中间件设计的完整套路。
一、前端认证的两种主流方式
|
模式 |
技术关键词 |
适用场景 |
|---|---|---|
|
Session + Cookie |
服务端记录状态,前端自动带 cookie |
同源、传统 Web 网站 |
|
Token (JWT) |
客户端存储 token,接口用 header 传 |
多端、前后端分离、跨域系统 |
区别:
|
项目 |
Cookie-Session |
Token-JWT |
|---|---|---|
|
状态存储 |
服务端 |
客户端 |
|
跨域 |
不方便 |
灵活支持 |
|
安全性 |
默认防重放 |
易泄漏(需搭配策略) |
|
可扩展 |
支持撤销、手动失效 |
更适合无状态服务 |
我们推荐在中后台/多端系统中优先使用 Token 模式(JWT)。
二、使用 JWT 实现登录认证
安装依赖:
npm i jsonwebtoken koa-jwt
生成 Token:
const jwt = require('jsonwebtoken');
const token = jwt.sign({ id: user.id }, 'secret-key', { expiresIn: '2h' });
验证 Token 中间件:
const jwtMiddleware = require('koa-jwt');
app.use(jwtMiddleware({ secret: 'secret-key' }).unless({
path: [/^\/public/, /^\/login/], // 免鉴权路由
}));
token 应该放在 Authorization header 中:
Authorization: Bearer xxx.token.yyy
三、如何统一封装鉴权中间件?
你可以封装一个权限控制中间件,例如:
const auth = () => async (ctx, next) => {
try {
if (!ctx.state.user) ctx.throw(401, '未登录');
await next();
} catch (err) {
ctx.status = err.status || 401;
ctx.body = { error: '认证失败,请重新登录' };
}
};
然后在受保护接口中使用:
router.get('/user/profile', auth(), async (ctx) => {
ctx.body = { user: ctx.state.user };
});
四、权限控制的“粒度”该怎么设计?
-
用户登录 ≠ 拥有操作权限
-
推荐添加角色字段 / 权限字段:
const user = { id: 1, role: 'admin', permissions: ['read', 'edit'] };
-
可封装权限判断器:
const permit = (permission) => async (ctx, next) => {
const perms = ctx.state.user?.permissions || [];
if (!perms.includes(permission)) ctx.throw(403, '无操作权限');
await next();
};
五、Token 失效、续期、登出如何处理?
|
问题 |
解决方式 |
|---|---|
|
Token 到期 |
expiresIn 控制过期时间 |
|
提前续期 |
后端提供 /refresh-token 接口 |
|
主动退出 |
客户端删除 token |
|
后台踢人 |
维护黑名单机制或使用 Redis session 状态控制 |
如果对安全性要求高,建议使用:
-
短效 Access Token + 长效 Refresh Token
-
Refresh Token 存储在 Cookie 中,Access Token 用于接口调用
六、是否应该将 Token 放在 Cookie?
可以(尤其是搭配 HttpOnly + Secure)
注意设置跨域 SameSite=None; Secure 属性,否则可能无法带上 Cookie
小结:
|
位置 |
安全性 |
灵活性 |
|---|---|---|
|
LocalStorage |
简单但易被 XSS 攻击 |
高 |
|
Cookie(HttpOnly) |
较安全(防 XSS) |
配置复杂 |
七、中间件的“组合拳”:验证、解析、权限、异常
构建完整认证体系的中间件链:
app.use(errorHandler()); // 全局错误捕获
app.use(jwtValidator()); // 鉴权处理
app.use(requestLogger()); // 日志记录
app.use(ctxUserExtractor()); // ctx.state.user 注入
中间件就是你的“安全战队”,合理组合能让你少写一堆 if。
总结:认证不是登录按钮,它是一套系统
你要解决的不只是“谁登录了”,而是:
-
登录了谁?能干啥?能干多久?出了问题怎么办?
-
是否可以安全、统一、可维护地进行用户身份验证?
Token 模式 + 中间件体系 + 合理封装,
是你走出“demo 项目”迈向“稳定系统”的关键一步。
844

被折叠的 条评论
为什么被折叠?



