16 KiB
16 KiB
安全认证
**本文引用的文件** - [backend/app/main.py](file://backend/app/main.py) - [backend/app/core/config.py](file://backend/app/core/config.py) - [backend/.env](file://backend/.env) - [backend/app/core/security.py](file://backend/app/core/security.py) - [backend/app/api/v1/auth.py](file://backend/app/api/v1/auth.py) - [backend/app/models/models.py](file://backend/app/models/models.py) - [backend/app/schemas/schemas.py](file://backend/app/schemas/schemas.py) - [backend/app/core/database.py](file://backend/app/core/database.py) - [backend/app/api/v1/__init__.py](file://backend/app/api/v1/__init__.py) - [test_frontend_connection.py](file://test_frontend_connection.py) - [frontend/public/test-api.html](file://frontend/public/test-api.html)目录
简介
本指南面向“医院绩效系统”的后端安全认证开发,聚焦以下主题:
- JWT 令牌生成、验证与过期处理
- 密码加密、盐值与安全存储
- 用户认证流程、权限验证与角色控制
- CORS 配置、跨域请求处理与安全头策略
- CSRF、XSS、SQL 注入等常见攻击的缓解思路
- 会话管理、令牌过期与安全审计
- OAuth2 集成、第三方认证与 SSO 支持建议
- 安全测试方法、漏洞扫描与安全加固建议
本指南在不泄露具体代码的前提下,结合仓库现有实现进行系统化梳理,并提供可视化图示与实操建议。
项目结构
后端采用 FastAPI + SQLAlchemy 2.x 异步 ORM 的分层架构,安全相关能力集中在核心模块与认证路由中:
- 应用入口与中间件:FastAPI 应用实例、CORS 中间件、全局异常处理
- 配置中心:环境变量与运行参数(含 JWT、CORS、数据库)
- 安全模块:JWT 编解码、密码哈希、当前用户解析与权限依赖
- 认证路由:登录、注册、个人信息查询
- 数据模型与模式:用户表、角色字段、令牌载荷
- 数据库会话:异步连接与依赖注入
graph TB
subgraph "应用层"
A["FastAPI 应用<br/>main.py"]
B["CORS 中间件<br/>main.py"]
end
subgraph "配置层"
C["系统配置<br/>core/config.py"]
D[".env 环境变量<br/>.env"]
end
subgraph "安全层"
E["JWT/密码/权限<br/>core/security.py"]
end
subgraph "认证路由"
F["认证路由<br/>api/v1/auth.py"]
end
subgraph "数据层"
G["数据库引擎/会话<br/>core/database.py"]
H["用户模型<br/>models/models.py"]
I["数据模式<br/>schemas/schemas.py"]
end
A --> B
A --> F
F --> E
E --> G
G --> H
C --> A
D --> C
E --> I
图表来源
- backend/app/main.py
- backend/app/core/config.py
- backend/.env
- backend/app/core/security.py
- backend/app/api/v1/auth.py
- backend/app/core/database.py
- backend/app/models/models.py
- backend/app/schemas/schemas.py
章节来源
核心组件
- JWT 与密码安全
- 使用 HS256 算法与对称密钥生成访问令牌;令牌包含过期时间与主体标识
- 使用 bcrypt 进行密码哈希与校验,自动处理盐值
- 提供从令牌解析当前用户的依赖函数,配合数据库查询与用户状态校验
- 认证路由
- 登录接口:用户名密码校验通过后签发访问令牌
- 注册接口:检查用户名唯一性,生成密码哈希并持久化
- 当前用户信息:基于依赖链完成身份与权限校验
- 配置与中间件
- CORS 允许指定前端源,支持凭证传递
- 全局异常处理记录日志并向上抛出
- 数据模型与模式
- 用户模型包含角色与激活状态字段,支撑角色与权限控制
- Pydantic 模式定义 Token 与用户响应结构
章节来源
- backend/app/core/security.py
- backend/app/api/v1/auth.py
- backend/app/core/config.py
- backend/app/main.py
- backend/app/models/models.py
- backend/app/schemas/schemas.py
架构总览
下图展示从浏览器到后端的关键交互路径,涵盖 CORS、认证、权限与数据库访问:
sequenceDiagram
participant FE as "前端应用"
participant API as "FastAPI 应用"
participant CORS as "CORS 中间件"
participant AUTH as "认证路由"
participant SEC as "安全模块"
participant DB as "数据库"
FE->>API : "OPTIONS /api/v1/auth/login"
API->>CORS : "CORS 预检检查"
CORS-->>FE : "允许的来源/方法/头"
FE->>AUTH : "POST /api/v1/auth/login"
AUTH->>SEC : "校验用户名/密码"
SEC->>DB : "查询用户并比对哈希"
DB-->>SEC : "返回用户记录"
SEC-->>AUTH : "生成访问令牌"
AUTH-->>FE : "返回 {access_token, token_type}"
FE->>API : "携带 Authorization : Bearer ..."
API->>SEC : "解析 JWT 并加载当前用户"
SEC->>DB : "按 ID 查询用户"
DB-->>SEC : "返回用户"
SEC-->>API : "返回当前用户对象"
图表来源
- backend/app/main.py
- backend/app/api/v1/auth.py
- backend/app/core/security.py
- backend/app/core/database.py
详细组件分析
JWT 令牌生成与验证
- 令牌生成
- 载荷包含过期时间与主体(用户 ID),使用对称密钥与指定算法签名
- 默认有效期可在配置中调整
- 令牌验证
- 解析阶段校验签名与过期时间
- 通过依赖注入从令牌提取主体并查询数据库获取用户对象
- 若令牌无效或用户不存在,抛出未授权异常
- 刷新机制
- 当前实现未提供刷新令牌的专用端点与逻辑
- 建议引入短期访问令牌与长期刷新令牌,配合黑名单/白名单与安全存储
flowchart TD
Start(["开始"]) --> Build["构建载荷<br/>设置过期时间/主体"]
Build --> Sign["使用 SECRET_KEY + ALGORITHM 签名"]
Sign --> Token["生成 access_token"]
Token --> Verify["接收 access_token"]
Verify --> Decode["解码并校验签名"]
Decode --> Expired{"是否过期?"}
Expired --> |是| Err["返回错误"]
Expired --> |否| LoadUser["按主体查询用户"]
LoadUser --> Found{"用户是否存在?"}
Found --> |否| Err
Found --> |是| Done(["返回当前用户"])
图表来源
章节来源
密码加密、盐值与安全存储
- 加密算法:bcrypt
- 盐值处理:由 bcrypt 自动生成并嵌入哈希结果
- 存储:用户模型保存完整哈希字符串
- 校验:登录时将明文密码与存储哈希进行比对
flowchart TD
In(["输入明文密码"]) --> Hash["bcrypt 生成哈希<br/>自动包含盐值"]
Hash --> Store["存储哈希字符串"]
Store --> VerifyIn(["登录输入明文密码"])
VerifyIn --> Compare["bcrypt 校验明文与存储哈希"]
Compare --> Result{"匹配?"}
Result --> |是| Allow["允许登录"]
Result --> |否| Deny["拒绝登录"]
图表来源
章节来源
用户认证流程与权限验证
- 认证流程
- 登录:提交用户名/密码,校验后签发访问令牌
- 注册:校验用户名唯一性,生成哈希并创建用户
- 获取当前用户:依赖链解析令牌、校验用户状态、返回用户信息
- 权限验证
- 当前活跃用户:校验用户是否启用
- 管理员:校验角色为 admin
- 管理者:校验角色为 admin 或 manager
- 角色控制
- 用户模型包含角色字段,路由层通过依赖强制权限
sequenceDiagram
participant U as "用户"
participant R as "认证路由"
participant S as "安全模块"
participant M as "模型/数据库"
U->>R : "POST /api/v1/auth/login"
R->>S : "verify_password()"
S->>M : "select user by username"
M-->>S : "返回用户(含哈希)"
S-->>R : "校验通过"
R->>S : "create_access_token(user.id)"
S-->>R : "返回 access_token"
R-->>U : "Token 响应"
U->>R : "GET /api/v1/auth/me"
R->>S : "get_current_active_user()"
S->>S : "decode_token() + 校验过期"
S->>M : "select user by id"
M-->>S : "返回用户"
S-->>R : "返回当前用户"
R-->>U : "用户信息响应"
图表来源
- backend/app/api/v1/auth.py
- backend/app/api/v1/auth.py
- backend/app/core/security.py
- backend/app/models/models.py
章节来源
- backend/app/api/v1/auth.py
- backend/app/api/v1/auth.py
- backend/app/core/security.py
- backend/app/models/models.py
CORS 配置与跨域请求处理
- CORS 中间件已在应用启动时注册,允许指定来源、凭证、方法与头
- 前端测试脚本通过 OPTIONS 预检与 POST 登录接口验证跨域行为
flowchart TD
Req["浏览器发起请求"] --> Preflight{"是否预检?"}
Preflight --> |是| Options["OPTIONS 预检"]
Options --> Check["CORS 中间件校验 Origin/Method/Headers"]
Check --> Allowed{"允许?"}
Allowed --> |是| Proceed["继续后续请求"]
Allowed --> |否| Block["拒绝请求"]
Preflight --> |否| Proceed
图表来源
章节来源
CSRF、XSS 与 SQL 注入防护
- CSRF
- 当前未见专门的 CSRF 令牌或 SameSite Cookie 设置
- 建议:对无状态 API,优先通过严格的 CORS 与来源校验;若使用 Cookie,启用 SameSite=Lax|Strict 并配合 CSRF 令牌
- XSS
- 建议:前端渲染严格转义、使用 CSP 头限制脚本来源、避免内联脚本
- SQL 注入
- 使用 SQLAlchemy 异步 ORM,参数化查询默认生效
- 建议:避免原生 SQL 拼接,统一通过 ORM 或带参查询执行器
章节来源
会话管理、令牌过期与安全审计
- 会话管理
- 采用无状态 JWT,无需服务端会话存储
- 令牌过期
- 令牌包含 exp 字段,默认有效期可配置
- 建议:在客户端妥善存储 access_token,并在 401 时触发重新登录
- 安全审计
- 建议:记录登录尝试、令牌签发/失效、敏感操作审计日志
- 当前全局异常处理器已记录 HTTP 与验证异常
章节来源
OAuth2 集成、第三方认证与 SSO 支持
- 当前实现基于 OAuth2 密码模式,令牌由后端签发
- 如需第三方认证(如 OIDC/SAML/SSO),建议:
- 引入第三方 SDK 或反向代理(如 Nginx + Keycloak)
- 将外部用户信息映射为内部用户角色与权限
- 保持对称密钥与算法的安全配置
章节来源
依赖关系分析
- 组件耦合
- 认证路由依赖安全模块与数据库会话
- 安全模块依赖配置与数据库,提供多级权限依赖
- 应用入口集中注册 CORS 与路由,异常处理统一
- 外部依赖
- JWT 编解码、密码哈希、异步数据库驱动
- 潜在问题
- 未发现循环依赖
- CORS 与安全头策略需与前端部署域名一致
graph LR
Auth["api/v1/auth.py"] --> Sec["core/security.py"]
Sec --> DB["core/database.py"]
Sec --> Model["models/models.py"]
Sec --> Conf["core/config.py"]
Main["app/main.py"] --> CORS["CORS 中间件"]
Main --> Auth
Conf --> Main
Env[".env"] --> Conf
图表来源
- backend/app/api/v1/auth.py
- backend/app/core/security.py
- backend/app/core/database.py
- backend/app/models/models.py
- backend/app/core/config.py
- backend/app/main.py
- backend/.env
章节来源
性能考量
- JWT 解析与数据库查询
- 令牌解析为内存操作;用户查询需一次数据库往返
- 建议:为用户表与索引字段建立合适索引,减少查询开销
- CORS 预检缓存
- 合理设置预检缓存时间,减少重复 OPTIONS 请求
- 会话与令牌
- 无状态 JWT 降低服务端压力;注意令牌大小与负载字段精简
故障排查指南
- 登录失败
- 检查用户名/密码是否正确,确认用户处于启用状态
- 查看后端日志定位异常
- 跨域问题
- 确认前端 Origin 是否在允许列表,预检请求是否返回允许头
- 令牌无效
- 检查令牌是否过期、算法与密钥是否匹配、主体是否正确
- 权限不足
- 确认用户角色满足所需权限依赖
章节来源
结论
本项目在安全认证方面具备清晰的分层与职责划分:JWT 与 bcrypt 的组合提供了可靠的令牌与密码安全;权限依赖链实现了基于角色的访问控制;CORS 中间件与异常处理提升了可用性与可观测性。建议在生产环境中进一步完善令牌刷新、CSRF 防护、安全头策略、审计日志与第三方认证集成,以满足更严格的安全要求。
附录
- 安全测试清单
- CORS 配置验证(预检与实际请求)
- 登录与鉴权端点的 401/403 场景
- 令牌过期与权限变更后的行为
- SQL 注入与 XSS 基线扫描
- 安全加固建议
- 生产环境替换默认密钥与最小长度要求
- 引入短期访问令牌与刷新令牌机制
- 启用 HTTPS、安全响应头、CSP
- 对高危操作增加二次确认与审计