完整流程(按时间顺序)
sequenceDiagram
participant U as 用户
participant FE as 前端 Vue
participant BE as 后端 Express
participant DB as MySQL
U->>FE: 输入账号密码
FE->>BE: POST /auth/login
BE->>DB: 查用户 + 校验密码哈希
BE->>BE: signToken({id, username, nickName})
BE-->>FE: { access_token }
FE->>FE: Pinia + Session 存 token
U->>FE: 访问业务页
FE->>FE: 路由守卫:有 token 才放行
FE->>BE: 业务请求 + Authorization: Bearer xxx
BE->>BE: authMiddleware 验签
BE-->>FE: 业务数据 / 401
1. 登录(后端)
POST /auth/login 不鉴权。
- 校验账号密码是否传了
- 查
sys_user(未删除) - 看锁定 / 过期状态
bcrypt比对密码signToken({ id, username, nickName }),密钥和过期时间来自环境变量- 返回
{ access_token }
对应:auth.controller.js + utils/jwt.js
2. 登录后(前端)
authStore.userLogin拿access_token- 写入 Pinia,并
Session持久化(刷新不丢) - Axios 请求拦截器:有 token 就加
Authorization: Bearer ${accessToken} - 路由守卫:无 token → 跳登录;有 token → 拉用户信息/菜单,动态加路由
对应:stores/auth.ts、utils/request.ts、router/permission.ts
3. 访问受保护接口(后端)
业务路由都挂了 authMiddleware:
- 读
Authorization,去掉Bearer - 没有 token → 401
jwt.verify成功 →req.user = payload,next()- 失败(过期、篡改)→ 401「登录已过期」
部分接口还会再过 permissionMiddleware,用 req.user.id 查权限码。
4. 退出
POST /auth/logout 需要带 token;后端目前是无状态 JWT,成功就返回,真正清状态在前端:删 token / 用户信息,再刷新。