ahserver/aidocs/auth_api.md
2025-10-05 12:07:12 +08:00

338 lines
9.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 技术文档:基于 `aiohttp` 的认证与会话管理系统
---
## 概述
本文档描述了一个基于 `aiohttp` 构建的异步 Web 应用中的 **用户认证Authentication****会话管理Session Management** 系统。该系统支持:
- 基于 Cookie 或 Redis 存储的会话机制
- 使用加密 Ticket 的安全认证策略(`TktAuthentication`
- 支持客户端唯一标识(`client_uuid`)绑定
- RSA 加密解密功能用于敏感数据处理
- 可扩展的权限检查接口
- 请求日志记录与异常追踪
该模块适用于需要高安全性、可扩展性和分布式部署能力的 Web 后端服务。
---
## 依赖库说明
| 包名 | 用途 |
|------|------|
| `aiohttp` | 异步 Web 框架核心 |
| `aiohttp_auth` / `TktAuthentication` | 基于票据ticket的身份认证中间件 |
| `aiohttp_session` | 会话管理中间件,支持多种存储后端 |
| `redis.asyncio` | 异步 Redis 客户端,用于持久化会话 |
| `cryptography`(隐式依赖) | 加密 Cookie 所需(由 `EncryptedCookieStorage` 内部使用) |
| `appPublic.*` | 自定义公共工具模块配置、日志、RSA 加解密等) |
> ⚠️ 注意:原代码中注释了 `aioredis`,实际使用的是新版本 `redis.asyncio`
---
## 核心功能模块
### 1. 会话管理Session Management
#### 支持两种会话存储方式:
| 存储类型 | 配置开关 | 特点 |
|--------|---------|------|
| 加密 Cookie 存储 | 默认启用 | 无外部依赖,适合单机部署 |
| Redis 存储 | `conf.website.session_redis.url` 存在时启用 | 支持集群、集中管理、更安全 |
#### 自定义 Redis 存储类:`MyRedisStorage`
继承自 `RedisStorage`,增强以下特性:
- **自定义 Session Key 生成逻辑**
- 优先从请求头 `client_uuid` 获取客户端唯一标识
- 若不存在,则随机生成 UUID4 并作为响应返回给客户端
- 对字符串 key 进行 hex 编码以保证兼容性
```python
def key_gen(self, request):
key = request.headers.get('client_uuid')
if not key:
key = uuid.uuid4().hex
return key
if isinstance(key, str):
key = key.encode('utf-8')
key = binascii.hexlify(key).decode('utf-8')
return key
```
> ✅ 目的:实现跨设备/浏览器的稳定会话识别,避免频繁重新登录。
---
### 2. 认证机制Authentication
使用 `aiohttp_auth.auth.ticket_auth.TktAuthentication` 实现基于时间戳和签名的票据认证。
#### 关键参数配置:
| 参数 | 默认值 | 配置项 | 说明 |
|------|-------|--------|------|
| `session_max_time` | 120 秒 | `website.session_max_time` | 会话最长有效期 |
| `reissue_time` | 30 秒 | `website.session_reissue_time` | 自动续签间隔 |
| `include_ip` | `True` | 固定设置 | 将客户端 IP 加入票据哈希,防劫持 |
#### 自定义 `_new_ticket` 方法
重写了票据创建过程,加入对 `client_uuid` 的支持:
```python
def _new_ticket(self, request, user_id):
client_uuid = request.headers.get('client_uuid')
ip = self._get_ip(request)
valid_until = int(time.time()) + self._max_age
return self._ticket.new(
user_id,
valid_until=valid_until,
client_ip=ip,
user_data=client_uuid # 将 client_uuid 附加到票据中
)
```
> 🔐 安全提示IP 绑定 + client_uuid 提升了会话安全性,防止 CSRF 和会话固定攻击。
---
### 3. 用户信息提取
提供异步函数用于从当前会话中获取用户信息。
#### 函数列表
| 函数 | 返回值 | 说明 |
|------|--------|------|
| `get_session_userinfo(request)` | `DictObject(userid, username, userorgid)` | 解析认证数据并封装为对象 |
| `get_session_user(request)` | `userid` 字符串 | 快速获取当前用户 ID |
> 💡 数据格式:认证信息以 `userid:username:userorgid` 形式存储于 ticket 中。
示例:
```python
await auth.remember(request, "U1001:alice:ORG789")
```
---
### 4. 登录与登出操作
#### `user_login(request, userid, username='', userorgid='')`
将用户信息编码后写入认证票据。
```python
ui = f'{userid}:{username}:{userorgid}'
await auth.remember(request, ui)
```
#### `user_logout(request)`
清除认证状态。
```python
await auth.forget(request)
```
> 🧽 清除的是服务器端票据与客户端 Cookie。
---
### 5. 权限控制中间件:`checkAuth`
通过 `@web.middleware` 装饰器注册为全局中间件,负责:
1. 记录访问开始时间
2. 获取当前用户身份
3. 调用 `checkUserPermission()` 判断是否有权访问路径
4. 记录耗时与异常信息
5. 控制响应流程或抛出 `HTTPUnauthorized` / `HTTPForbidden`
#### 日志输出示例
```text
INFO timecost=client(192.168.1.100) U1001 access /api/data cost 0.045, (0.002)
ERROR Exception=client(192.168.1.100) U1001 access /api/admin/delete cost 0.12, (0.003), except=ValueError...
```
> ✅ 成功请求记录总耗时及权限判断耗时;异常则完整打印 traceback。
---
### 6. RSA 加解密支持
#### 类方法:`AuthAPI`
| 方法 | 功能 |
|------|------|
| `getPrivateKey()` | 延迟加载私钥文件(仅首次调用读取),避免重复 IO |
| `rsaDecode(cdata)` | 使用私钥解密 Base64 编码的数据 |
依赖:
- `appPublic.rsawrap.RSA`:封装了 PyCryptodome 的 RSA 操作
- 配置路径:`conf.website.rsakey.privatekey`
典型用途:解密前端传来的加密密码或其他敏感字段。
---
### 7. 初始化与集成:`setupAuth(app)`
此方法完成整个认证系统的初始化,步骤如下:
1. **构建 secret 密钥**
基于端口号拼接固定字符串,补足 32 字节用于 AES 加密Cookie Storage 所需)
2. **选择会话存储方式**
```python
if self.conf.website.session_redis:
redisdb = await redis.Redis.from_url(url)
storage = MyRedisStorage(redisdb)
else:
storage = EncryptedCookieStorage(secret)
```
3. **安装会话中间件**
```python
aiohttp_session.setup(app, storage)
```
4. **配置 Ticket 认证策略**
```python
policy = SessionTktAuthentication(
secret=secret,
max_age=session_max_time,
reissue_time=session_reissue_time,
include_ip=True
)
auth.setup(app, policy)
```
5. **替换默认 IP 获取逻辑**
```python
TktAuthentication._get_ip = get_client_ip # 使用 request['client_ip']
```
6. **注入权限检查中间件**
```python
app.middlewares.append(self.checkAuth)
```
---
## 配置要求(`jsonConfig` 结构)
`getConfig()` 应返回包含以下字段的配置对象:
```json
{
"website": {
"port": 8080,
"rsakey": {
"privatekey": "/path/to/private.pem"
},
"session_max_time": 3600,
"session_reissue_time": 1800,
"session_redis": {
"url": "redis://localhost:6379/0"
}
}
}
```
> ⚠️ 若未设置 `session_redis.url`,则自动降级为本地加密 Cookie 存储。
---
## 使用方式(集成到 AIOHTTP 应用)
```python
from aiohttp import web
from your_module import AuthAPI
async def init_app():
app = web.Application()
auth_api = AuthAPI()
await auth_api.setupAuth(app)
# 添加路由
# app.router.add_get('/protected', protected_handler)
return app
if __name__ == '__main__':
web.run_app(init_app(), port=8080)
```
---
## 安全建议
| 项目 | 推荐做法 |
|------|----------|
| Secret Key | 不应硬编码,建议从环境变量或密钥管理系统加载 |
| client_uuid | 前端应在首次访问时生成并持久化localStorage每次请求带上 |
| Redis 安全 | 开启密码认证、限制网络访问 |
| 日志敏感信息 | 禁止记录用户密码、token 明文 |
| HTTPS | 生产环境必须启用 TLS防止 Cookie 被窃听 |
---
## 扩展接口
### `checkUserPermission(request, user, path)`
抽象方法,子类可覆盖实现 RBAC、ACL 等权限模型。
```python
async def checkUserPermission(self, request, user, path):
# 示例:仅允许特定用户访问管理员接口
if path.startswith("/admin") and user != "admin":
return False
return True
```
### `needAuth(path)`
预留钩子,未来可用于跳过某些路径的认证检查。
---
## 错误处理
| 异常场景 | 处理方式 |
|--------|---------|
| 未登录访问受保护资源 | 抛出 `HTTPUnauthorized (401)` |
| 有登录但无权限 | 抛出 `HTTPForbidden (403)` |
| 内部错误 | 捕获并记录 traceback重新抛出异常 |
| Redis 连接失败 | 初始化阶段抛出异常,应用无法启动 |
---
## 性能考量
- **Redis 存储模式**:增加一次网络往返,但支持横向扩展
- **Ticket 验证**:轻量级 HMAC 验证,性能优异
- **自动续签机制**:每 `reissue_time` 秒更新票据,延长会话寿命而不影响用户体验
---
## 总结
本模块提供了一套完整的、安全的、可扩展的异步认证解决方案,特点包括:
✅ 支持分布式部署Redis
✅ 客户端绑定UUID + IP提升安全性
✅ 细粒度权限控制接口
✅ 全链路日志跟踪与性能监控
✅ 支持 RSA 解密敏感数据
适用于企业级后台管理系统、API 网关、微服务认证中心等场景。
---
> 📝 文档版本v1.0
> © 2025 公共技术组件团队