Skip to content

认证与授权

概述

系统采用 JWT + Redis 的认证方案,支持多设备登录控制、Token 刷新、OAuth2 多平台登录。

认证流程

┌──────────┐    POST /login     ┌──────────┐
│  客户端   │ ───────────────→  │  后端     │
│          │ ←───────────────  │          │
│          │   accessToken     │ 1. 验证密码│
│          │   refreshToken    │ 2. 生成JWT │
│          │                   │ 3. 缓存Redis│
│          │                   └──────────┘
│          │   请求头 Bearer
│          │ ───────────────→  ┌──────────┐
│          │                   │ 中间件    │
│          │                   │ 1. 解析JWT │
│          │                   │ 2. Redis读│
│          │                   │   角色信息 │
│          │                   │ 3. 权限检查│
└──────────┘                   └──────────┘

JWT Token 设计

Token 结构

Token 中仅存储身份标识,不存储角色等动态信息:

python
token_data = {
    "sub": user.id,           # 用户ID
    "username": user.username, # 用户名
    "device_id": device_id,   # 设备标识
    "exp": expire_time,       # 过期时间
    "type": "access"          # Token类型
}

Token 配置

配置项默认值说明
JWT_SECRET_KEY-JWT 密钥(生产环境必须修改)
JWT_ALGORITHMHS256加密算法
ACCESS_TOKEN_EXPIRE_MINUTES1440Access Token 过期时间(24小时)
REFRESH_TOKEN_EXPIRE_DAYS7Refresh Token 过期时间(7天)
ALLOW_MULTI_DEVICE_LOGINTrue是否允许多设备同时登录

Redis 存储

登录成功后,在 Redis 中存储以下信息:

Key过期时间说明
refresh_token:{user_id}:{device_id}7天Refresh Token
access_token:{user_id}:{device_id}24小时Access Token
device_info:{user_id}:{device_id}7天设备信息 Hash
user_info_cache:{user_id}-用户角色等动态信息

登录接口

JSON 登录

POST /api/core/login
Content-Type: application/json

{
  "username": "admin",
  "password": "123456"
}

OAuth2 登录(Swagger 用)

POST /api/core/login/oauth2
Content-Type: application/x-www-form-urlencoded

username=admin&password=123456

登录响应

json
{
  "accessToken": "eyJhbGciOi...",
  "refreshToken": "eyJhbGciOi...",
  "tokenType": "bearer",
  "expireTime": 86400
}

登录流程

  1. 验证用户:用户名 + 密码(bcrypt 加密)
  2. 检查状态:is_active、user_status(0=禁用、1=正常、2=锁定)
  3. 生成 Token:Access Token + Refresh Token(包含 device_id)
  4. 缓存信息:用户角色信息写入 Redis
  5. 设备管理:单设备模式下清除其他设备 Token
  6. 记录日志:登录日志(IP、浏览器、设备类型)

Token 刷新

POST /api/core/refresh_token
Content-Type: application/json

{
  "refresh_token": "eyJhbGciOi..."
}

并发刷新处理:刷新时保留上一个 Token 60 秒(prev 键),防止并发请求导致 Token 失效。

多设备登录控制

通过 ALLOW_MULTI_DEVICE_LOGIN 配置:

  • True(默认):允许多设备同时在线
  • False:新登录时清除该用户所有旧设备的 Token

设备标识基于 User-Agent + IP 生成。

OAuth2 多平台登录

支持 10+ OAuth 平台:

平台配置前缀说明
GiteeGITEE_Gitee 登录
GitHubGITHUB_GitHub 登录
QQQQ_QQ 登录
GoogleGOOGLE_Google 登录
微信WECHAT_微信开放平台
MicrosoftMICROSOFT_Microsoft 登录
钉钉DINGTALK_钉钉登录
飞书FEISHU_飞书登录
企业微信WECOM_企业微信登录

每个平台需要配置 CLIENT_IDCLIENT_SECRETREDIRECT_URI

OAuth 登录流程:

  1. 前端跳转到平台授权页
  2. 用户授权后回调到 REDIRECT_URI
  3. 后端用 code 换取用户信息
  4. 自动创建/关联用户
  5. 生成 JWT Token 返回

认证中间件

AuthPermissionMiddleware 在每个请求前执行:

  1. 白名单检查/login/docs/openapi.json 等路径跳过认证
  2. 解析 Token:从 Authorization: Bearer {token} 提取并验证 JWT
  3. 加载用户信息:从 Redis 获取角色、部门等信息
  4. 注入请求上下文:将 user_idrole_idsdept_idis_superuser 写入 request.state
python
# 在 API 中获取当前用户信息
@router.get("/")
async def get_data(request: Request):
    user_id = request.state.user_id
    role_ids = request.state.role_ids
    dept_id = request.state.dept_id
    is_superuser = request.state.is_superuser

权限系统

三级权限体系

操作权限 (Permission)
  └── 控制用户能执行哪些操作(查看/新增/编辑/删除/导出/导入)

数据权限 (Data Scope)
  └── 控制用户能看到哪些数据(全部/本人/本部门/本部门及子部门/自定义)

字段权限 (Field Permission)
  └── 控制用户能看到哪些字段(可写/只读/隐藏/脱敏)

操作权限

基于 RBAC(角色-权限模型):

用户 → 角色 → 权限 → 菜单/操作

权限编码格式:form:{form_code}:{action}

action说明
view查看
add新增
edit编辑
delete删除
export导出
import导入

数据权限

通过 ResourceDataScopeConfig 绑定到资源类型:

scope_type说明
all全部数据
self仅本人创建的数据
dept本部门数据
dept_and_children本部门及子部门数据
custom自定义部门范围

字段权限

通过 ResourceFieldPermission 绑定到角色和资源类型:

权限级别说明
write可读写
read只读
hidden隐藏(不返回该字段)
masked脱敏(如手机号显示为 138****8888

脱敏规则:

  • 手机号:保留前 3 后 4
  • 邮箱:保留前 2 后域名
  • 身份证:保留前 3 后 4
  • 姓名:保留首字
  • 默认:保留前 2 后 2

Released under the MIT License.