- 新增文档模板和导航结构 - 实现服务器基础API路由和控制器 - 添加扩展插件配置和前端框架 - 引入多租户和权限管理模块 - 集成日志和数据库配置 - 添加核心业务模型和类型定义
349 lines
8.9 KiB
Markdown
349 lines
8.9 KiB
Markdown
# AuthService 文档
|
||
|
||
## 概述
|
||
|
||
AuthService 是一个功能强大的认证服务,支持 JWT、OAuth2.0 和多因子认证(MFA),为 Crawlful Hub 项目提供统一的身份认证和授权管理。
|
||
|
||
## 核心功能
|
||
|
||
### 1. JWT 认证
|
||
- 生成和验证 JWT 令牌
|
||
- 支持令牌刷新
|
||
- 携带 4-tuple TraceContext(tenantId, shopId, taskId, traceId)
|
||
|
||
### 2. OAuth2.0 认证
|
||
- 客户端管理
|
||
- 授权码流程
|
||
- 访问令牌生成和刷新
|
||
- 支持多种授权类型
|
||
|
||
### 3. 多因子认证(MFA)
|
||
- 基于时间的一次性密码(TOTP)
|
||
- 支持 SMS 和 EMAIL 验证(预留接口)
|
||
|
||
## 数据库表结构
|
||
|
||
### cf_user
|
||
- id: 用户ID
|
||
- username: 用户名
|
||
- password_hash: 密码哈希
|
||
- role: 角色
|
||
- tenant_id: 租户ID
|
||
- shop_id: 店铺ID(可选)
|
||
- status: 状态(ACTIVE/DISABLED)
|
||
- created_at: 创建时间
|
||
- updated_at: 更新时间
|
||
|
||
### cf_oauth_client
|
||
- id: 客户端ID
|
||
- client_id: 客户端标识符
|
||
- client_secret: 客户端密钥哈希
|
||
- redirect_uri: 重定向URI
|
||
- grant_types: 授权类型
|
||
- scope: 权限范围
|
||
- tenant_id: 租户ID
|
||
- created_at: 创建时间
|
||
- updated_at: 更新时间
|
||
|
||
### cf_oauth_code
|
||
- id: 授权码ID
|
||
- code: 授权码
|
||
- client_id: 客户端ID
|
||
- user_id: 用户ID
|
||
- redirect_uri: 重定向URI
|
||
- scope: 权限范围
|
||
- expires_at: 过期时间
|
||
- created_at: 创建时间
|
||
- updated_at: 更新时间
|
||
|
||
### cf_oauth_token
|
||
- id: 令牌ID
|
||
- access_token: 访问令牌
|
||
- refresh_token: 刷新令牌
|
||
- client_id: 客户端ID
|
||
- user_id: 用户ID
|
||
- scope: 权限范围
|
||
- expires_at: 过期时间
|
||
- created_at: 创建时间
|
||
- updated_at: 更新时间
|
||
|
||
### cf_user_mfa
|
||
- id: MFA记录ID
|
||
- user_id: 用户ID
|
||
- method: 认证方法(TOTP/SMS/EMAIL)
|
||
- secret: 密钥
|
||
- enabled: 是否启用
|
||
- created_at: 创建时间
|
||
- updated_at: 更新时间
|
||
|
||
### cf_refresh_token
|
||
- id: 刷新令牌ID
|
||
- user_id: 用户ID
|
||
- token: 刷新令牌
|
||
- expires_at: 过期时间
|
||
- created_at: 创建时间
|
||
- updated_at: 更新时间
|
||
|
||
## API 接口
|
||
|
||
### 公开接口
|
||
|
||
#### POST /api/auth/login
|
||
- 功能:用户登录
|
||
- 请求参数:
|
||
- username: 用户名
|
||
- password: 密码
|
||
- 响应:
|
||
- token: JWT令牌
|
||
- refreshToken: 刷新令牌
|
||
- user: 用户信息
|
||
|
||
#### POST /api/auth/refresh
|
||
- 功能:刷新令牌
|
||
- 请求参数:
|
||
- refreshToken: 刷新令牌
|
||
- 响应:
|
||
- token: 新的JWT令牌
|
||
- user: 用户信息
|
||
|
||
#### POST /api/auth/register
|
||
- 功能:注册新用户
|
||
- 请求参数:
|
||
- username: 用户名
|
||
- password: 密码
|
||
- role: 角色
|
||
- tenantId: 租户ID
|
||
- shopId: 店铺ID(可选)
|
||
- 响应:
|
||
- user: 用户信息
|
||
|
||
#### POST /api/auth/oauth2/token
|
||
- 功能:获取OAuth2.0访问令牌
|
||
- 请求参数:
|
||
- grant_type: 授权类型(authorization_code/refresh_token)
|
||
- code: 授权码(当grant_type为authorization_code时)
|
||
- refresh_token: 刷新令牌(当grant_type为refresh_token时)
|
||
- client_id: 客户端ID
|
||
- client_secret: 客户端密钥
|
||
- redirect_uri: 重定向URI
|
||
- 响应:
|
||
- access_token: 访问令牌
|
||
- refresh_token: 刷新令牌
|
||
- expires_in: 过期时间(秒)
|
||
- scope: 权限范围
|
||
|
||
### 需要认证的接口
|
||
|
||
#### GET /api/auth/me
|
||
- 功能:获取当前用户信息
|
||
- 响应:
|
||
- user: 用户信息
|
||
|
||
#### POST /api/auth/mfa/enable
|
||
- 功能:启用多因子认证
|
||
- 请求参数:
|
||
- method: 认证方法(TOTP/SMS/EMAIL)
|
||
- secret: 密钥
|
||
- 响应:
|
||
- success: 是否成功
|
||
|
||
#### POST /api/auth/mfa/verify
|
||
- 功能:验证多因子认证码
|
||
- 请求参数:
|
||
- method: 认证方法(TOTP/SMS/EMAIL)
|
||
- code: 验证码
|
||
- 响应:
|
||
- success: 是否成功
|
||
|
||
#### GET /api/auth/oauth2/authorize
|
||
- 功能:OAuth2.0授权
|
||
- 请求参数:
|
||
- client_id: 客户端ID
|
||
- redirect_uri: 重定向URI
|
||
- scope: 权限范围
|
||
- state: 状态参数
|
||
- 响应:
|
||
- 重定向到redirect_uri,携带code和state参数
|
||
|
||
#### POST /api/auth/oauth2/client
|
||
- 功能:创建OAuth2.0客户端
|
||
- 请求参数:
|
||
- clientId: 客户端ID
|
||
- clientSecret: 客户端密钥
|
||
- redirectUri: 重定向URI
|
||
- grantTypes: 授权类型
|
||
- scope: 权限范围
|
||
- 响应:
|
||
- success: 是否成功
|
||
|
||
## 使用示例
|
||
|
||
### JWT 认证
|
||
|
||
```typescript
|
||
// 登录
|
||
const loginResponse = await fetch('/api/auth/login', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify({
|
||
username: 'admin',
|
||
password: 'admin123'
|
||
})
|
||
});
|
||
|
||
const { token, refreshToken, user } = await loginResponse.json();
|
||
|
||
// 使用令牌访问受保护的接口
|
||
const protectedResponse = await fetch('/api/auth/me', {
|
||
headers: {
|
||
'Authorization': `Bearer ${token}`
|
||
}
|
||
});
|
||
|
||
// 刷新令牌
|
||
const refreshResponse = await fetch('/api/auth/refresh', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify({
|
||
refreshToken
|
||
})
|
||
});
|
||
|
||
const { token: newToken } = await refreshResponse.json();
|
||
```
|
||
|
||
### OAuth2.0 认证
|
||
|
||
```typescript
|
||
// 1. 重定向用户到授权页面
|
||
const authorizationUrl = `/api/auth/oauth2/authorize?client_id=client1&redirect_uri=http://localhost:3000/callback&scope=read%20write&state=12345`;
|
||
window.location.href = authorizationUrl;
|
||
|
||
// 2. 处理回调(在redirect_uri指定的页面)
|
||
const urlParams = new URLSearchParams(window.location.search);
|
||
const code = urlParams.get('code');
|
||
const state = urlParams.get('state');
|
||
|
||
// 3. 使用授权码获取访问令牌
|
||
const tokenResponse = await fetch('/api/auth/oauth2/token', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify({
|
||
grant_type: 'authorization_code',
|
||
code,
|
||
client_id: 'client1',
|
||
client_secret: 'secret1',
|
||
redirect_uri: 'http://localhost:3000/callback'
|
||
})
|
||
});
|
||
|
||
const { access_token, refresh_token, expires_in, scope } = await tokenResponse.json();
|
||
|
||
// 4. 使用访问令牌访问受保护的接口
|
||
const protectedResponse = await fetch('/api/protected', {
|
||
headers: {
|
||
'Authorization': `Bearer ${access_token}`
|
||
}
|
||
});
|
||
|
||
// 5. 使用刷新令牌获取新的访问令牌
|
||
const refreshResponse = await fetch('/api/auth/oauth2/token', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify({
|
||
grant_type: 'refresh_token',
|
||
refresh_token,
|
||
client_id: 'client1',
|
||
client_secret: 'secret1'
|
||
})
|
||
});
|
||
|
||
const { access_token: newAccessToken } = await refreshResponse.json();
|
||
```
|
||
|
||
### 多因子认证
|
||
|
||
```typescript
|
||
// 1. 生成TOTP密钥
|
||
const { secret, otpauthUrl } = AuthService.generateTOTPSecret();
|
||
|
||
// 2. 启用MFA
|
||
const enableResponse = await fetch('/api/auth/mfa/enable', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'Authorization': `Bearer ${token}`
|
||
},
|
||
body: JSON.stringify({
|
||
method: 'TOTP',
|
||
secret
|
||
})
|
||
});
|
||
|
||
// 3. 验证MFA码
|
||
const verifyResponse = await fetch('/api/auth/mfa/verify', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'Authorization': `Bearer ${token}`
|
||
},
|
||
body: JSON.stringify({
|
||
method: 'TOTP',
|
||
code: '123456' // 从认证器应用获取
|
||
})
|
||
});
|
||
|
||
const { success } = await verifyResponse.json();
|
||
```
|
||
|
||
## 安全注意事项
|
||
|
||
1. **密码安全**:使用 bcrypt 对密码进行哈希处理,避免明文存储
|
||
2. **令牌安全**:JWT 令牌和 OAuth2.0 令牌都有过期时间,避免长期使用
|
||
3. **密钥管理**:JWT 密钥和 MFA 密钥应该妥善保管,避免泄露
|
||
4. **权限控制**:基于角色的访问控制(RBAC),确保用户只能访问授权的资源
|
||
5. **输入验证**:所有用户输入都应该进行验证,避免注入攻击
|
||
6. **HTTPS**:在生产环境中使用 HTTPS,避免数据传输过程中的窃听
|
||
|
||
## 部署配置
|
||
|
||
### 环境变量
|
||
|
||
- `JWT_SECRET`:JWT 签名密钥,生产环境中应该使用强随机字符串
|
||
- `JWT_EXPIRES_IN`:JWT 令牌过期时间,默认 24h
|
||
- `REFRESH_TOKEN_EXPIRES_IN`:刷新令牌过期时间,默认 7d
|
||
- `OAUTH2_ACCESS_TOKEN_EXPIRES_IN`:OAuth2.0 访问令牌过期时间,默认 1h
|
||
- `OAUTH2_AUTH_CODE_EXPIRES_IN`:OAuth2.0 授权码过期时间,默认 10m
|
||
|
||
### 数据库配置
|
||
|
||
- 使用 MySQL 8.0
|
||
- 所有表都以 `cf_` 为前缀
|
||
- 建立适当的索引,提高查询性能
|
||
- 使用外键约束,确保数据完整性
|
||
|
||
## 故障排查
|
||
|
||
### 常见问题
|
||
|
||
1. **令牌过期**:如果收到 401 Unauthorized 错误,检查令牌是否过期,使用刷新令牌获取新令牌
|
||
2. **密码错误**:如果登录失败,检查用户名和密码是否正确
|
||
3. **MFA 验证失败**:检查 TOTP 码是否正确,确保时间同步
|
||
4. **OAuth2.0 授权失败**:检查客户端 ID、密钥和重定向 URI 是否正确
|
||
|
||
### 日志
|
||
|
||
AuthService 会记录所有认证相关的操作和错误,日志文件位于 `logs/` 目录下,可以通过查看日志来排查问题。
|
||
|
||
## 总结
|
||
|
||
AuthService 是一个功能完整、安全可靠的认证服务,支持多种认证方式,为 Crawlful Hub 项目提供统一的身份认证和授权管理。通过合理使用 AuthService,可以确保系统的安全性和可靠性,同时为用户提供良好的认证体验。
|