Skip to content

登录与会话

纯前端商业版提供完整的前端认证链路,但不绑定特定后端语言或身份平台。所有认证 HTTP 接口统一放在 src/api/auth.ts,请求层负责附加 Token,路由守卫负责恢复用户和权限,客户后端负责真正的身份校验与会话安全。

认证链路

核心文件:

text
src/api/auth.ts
src/services/auth.ts       # 现有认证流程封装,不存放接口定义
src/utils/http/index.ts
src/store/modules/user.ts
src/router/guards/beforeEach.ts

依赖方向如下:

text
登录页 / 路由守卫
  -> 现有认证流程封装
  -> src/api/auth.ts
  -> 统一 HTTP 请求层
  -> 客户后端

页面不应直接操作 LocalStorage,也不应自行拼接 Authorization 请求头。

接口目录规则

登录、退出、当前用户、验证码和 Refresh Token 等请求函数全部放在 src/api/auth.tssrc/services/auth.ts 只能调用这些 API 并组合认证流程,不能定义新的请求 URL。

登录流程

text
提交账号密码
  -> POST /api/v1/auth/signin
  -> 校验 accessToken 为非空字符串
  -> userStore 保存 Access Token
  -> 跳转目标路由
  -> 路由守卫获取当前用户
  -> 初始化角色、按钮权限、菜单和动态路由

登录接口请求:

json
{
  "username": "Super",
  "password": "123456"
}

响应 data 至少包含:

json
{
  "accessToken": "your-access-token"
}

当前认证流程会在调用 src/api/auth.ts 后拒绝空字符串或格式错误的 Token,避免无效登录态进入后续路由流程。

当前用户接口

登录后和页面刷新时,系统都会调用:

text
GET /api/v1/user/info
Authorization: Bearer <accessToken>

核心响应:

json
{
  "id": 1,
  "username": "Super",
  "email": "super@example.com",
  "roles": ["R_SUPER"],
  "buttons": ["*"]
}

前端会校验:

  • id 必须是有限数字。
  • username 必须是非空字符串。
  • email 必须是字符串。
  • rolesbuttons 必须是非空字符串组成的数组。
  • buttons 使用 * 时不能再混合其他权限码。

严格校验可以让后端契约错误尽早暴露,避免畸形权限数据造成错误展示或意外放行。

页面刷新与会话恢复

用户 Store 持久化 Access Token,但不长期持久化完整用户资料和权限:

text
刷新页面
  -> Pinia 恢复 Access Token
  -> 恢复本地 Access Token
  -> 路由守卫请求当前用户
  -> 使用最新角色和按钮权限重建菜单

这样处理有两个直接收益:

  1. 用户权限在服务端变化后,刷新即可获得最新结果。
  2. 浏览器不会长期使用一份过期的用户和权限快照。

当前只实现 Access Token

项目没有内置 Refresh Token、静默续期或并发刷新队列。Access Token 过期后,由 401 流程清理登录态并返回登录页。

请求携带 Token

统一请求层从 userStore 读取 Token,并添加:

http
Authorization: Bearer <accessToken>

认证之外的业务 API 不需要重复编写 Token 逻辑:

ts
import request from '@/utils/http'

export function fetchProfile() {
  return request.get<Api.Account.Profile>({
    url: '/api/v1/account/profile'
  })
}

如果客户后端使用 Cookie 会话,应统一调整请求层和 VITE_WITH_CREDENTIALS,而不是在个别 API 上混用两套认证方式。

401 与退出登录

请求层收到业务码或 HTTP 状态 401 时,会触发统一登出:

text
401
  -> 清理 Access Token 和用户信息
  -> 清理动态路由与菜单状态
  -> 清理跨账号敏感偏好
  -> 跳转登录页并携带原目标地址

用户主动退出时会调用:

text
POST /api/v1/auth/logout

无论后端退出请求是否成功,前端最终都应清理本地认证状态。后端则负责撤销服务端会话或使令牌失效。

权限与认证的边界

登录成功只证明用户获得了一个可用于请求的令牌,不代表用户拥有所有页面和操作权限:

  • roles 决定本地菜单过滤和角色指令。
  • buttons 决定按钮、操作项和前端交互展示。
  • 菜单树决定当前用户可见的业务入口。
  • 后端必须继续校验每个数据接口和写操作。

前端权限用于改善体验,不能作为数据安全边界。完整模型见路由与权限

扩展 Refresh Token

客户后端需要双令牌协议时,建议把扩展限制在以下位置:

  1. 在认证 API 中增加刷新接口。
  2. 在用户 Store 中统一保存和清理双令牌。
  3. 在 HTTP 层实现单实例刷新任务和失败请求队列。
  4. 刷新失败时进入现有统一登出流程。
  5. 避免多个并发 401 同时发起刷新请求。

不要让页面组件感知 Refresh Token,也不要在每个 API 文件中重复刷新逻辑。

项目未内置的协议

当前源码没有内置以下能力:

  • RSA 密码加密
  • 请求签名、Nonce、时间戳校验
  • 图形验证码协议
  • OAuth/OIDC 跳转流程
  • Refresh Token 自动续期

这些能力与客户后端、安全策略和身份平台高度相关,应该在明确协议后接入。生产环境至少必须使用 HTTPS,不能把前端加密当作传输安全的替代品。

联调检查

  • 登录接口返回非空 accessToken
  • 当前用户字段通过前端校验。
  • 刷新受保护页面后能恢复菜单。
  • 无效 Token 返回 401,而不是返回空用户。
  • 主动退出后旧 Token 无法继续访问后端接口。
  • 不同账号切换时不会继承上一个账号的敏感状态。

接口响应和 Axios 行为见接口接入,状态持久化细节见状态管理

根据 MIT 许可证发布