Metadata-Version: 2.3
Name: soulseal
Version: 0.1.11
Summary: 这是一套适合Python快速开发的身份管理模块，SoulSeal 取自修仙小说中的「灵魂烙印」。
Author: arcstep
Author-email: 43801@qq.com
Requires-Python: >=3.11
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Dist: aiohttp (>=3.11.16,<4.0.0)
Requires-Dist: argon2-cffi (>=23.1.0,<24.0.0)
Requires-Dist: async-timeout (>=5.0.1,<6.0.0)
Requires-Dist: email-validator (>=2.2.0,<3.0.0)
Requires-Dist: fastapi (>=0.115.9,<0.116.0)
Requires-Dist: httpx (>=0.28.1,<0.29.0)
Requires-Dist: pydantic (>=2.11.3,<3.0.0)
Requires-Dist: pyjwt (>=2.10.1,<3.0.0)
Requires-Dist: requests (>=2.32.3,<3.0.0)
Requires-Dist: responses (>=0.25.7,<0.26.0)
Requires-Dist: uvicorn (>=0.34.0,<0.35.0)
Requires-Dist: voidring (>=0.1.3,<0.2.0)
Description-Content-Type: text/markdown

# SoulSeal

这是一套适合Python+FastAPI快速集成的身份管理模块，SoulSeal 取自修仙小说中的「灵魂烙印」。使用RocksDB存储用户数据，无需额外配置关系型数据库。

## 快速开始

### 作为独立的身份认证中心启动

```bash
# 使用Poetry启动（推荐）
poetry run soulseal

# 使用自定义参数
poetry run soulseal --host 0.0.0.0 --port 8080 --token-storage-method header
```

### 命令行参数与环境变量

所有参数均可通过命令行或环境变量（SOULSEAL_参数名）设置：

| 参数 | 环境变量 | 说明 | 默认值 |
|-----|---------|------|-------|
| --data-dir | SOULSEAL_DATA_DIR | 数据目录 | ~/.soulseal |
| --host | SOULSEAL_HOST | 主机地址 | 127.0.0.1 |
| --port | SOULSEAL_PORT | 端口 | 8000 |
| --prefix | SOULSEAL_PREFIX | API前缀 | /api |
| --cors-origins | SOULSEAL_CORS_ORIGINS | CORS源(逗号分隔) | http://localhost:3000,... |
| --jwt-secret-key | SOULSEAL_JWT_SECRET_KEY | JWT密钥 | - |
| --token-storage-method | SOULSEAL_TOKEN_STORAGE_METHOD | 令牌存储方式 | cookie |

## API端点

SoulSeal提供以下API端点（假设前缀为`/api`）：

| 路径 | 方法 | 描述 | 授权 |
|------|------|------|-----|
| `/api/auth/register` | POST | 用户注册 | 否 |
| `/api/auth/login` | POST | 用户登录 | 否 |
| `/api/auth/logout` | POST | 用户退出 | 是 |
| `/api/auth/profile` | GET/POST | 获取/更新用户信息 | 是 |
| `/api/auth/refresh-token` | POST | 刷新访问令牌 | 否 |

## 在FastAPI应用中集成

### 1. 作为中间件集成

```python
from fastapi import FastAPI
from soulseal.start import create_app

app = create_app(
    db_path="/path/to/db",  # RocksDB数据库路径
    title="我的API",
    prefix="/api",
    jwt_secret_key="your-secret-key",
    token_storage_method="cookie"  # 可选: cookie, header, both
)

# 添加自己的路由
@app.get("/hello")
def hello():
    return {"message": "Hello World"}
```

### 2. 保护你的路由

使用TokenSDK验证令牌（推荐）：

```python
from fastapi import FastAPI, Depends, HTTPException
from soulseal.tokens import TokenSDK

app = FastAPI()
token_sdk = TokenSDK(jwt_secret_key="your-secret-key")

# 验证函数
async def verify_token(request: Request, response: Response):
    token = token_sdk.extract_token_from_request(request)
    if not token:
        raise HTTPException(status_code=401, detail="未提供令牌")
    
    verify_result = token_sdk.verify_token(token)
    if verify_result.is_fail():
        raise HTTPException(status_code=401, detail=verify_result.error)
    
    return verify_result.data

@app.get("/protected")
async def protected_route(token_data = Depends(verify_token)):
    return {"message": f"你好，{token_data['username']}!"}
```

也可以使用require_user函数（适合完整集成环境）：

```python
from fastapi import Depends
from soulseal import require_user

@app.get("/admin")
def admin_route(user_data = Depends(require_user(tokens_manager, require_roles=["admin"]))):
    return {"message": "管理员页面"}
```

## 令牌存储方式

SoulSeal支持三种令牌存储方式，可通过`token_storage_method`参数设置：

- **cookie模式**（默认）：将令牌存储在HTTP Cookie中
  - 优点：简单，前端无需处理
  - 适合：传统Web应用

- **header模式**：将令牌通过HTTP响应头返回
  - 优点：适合前后端分离、跨域应用
  - 适合：React/Vue等单页应用

- **both模式**：同时使用Cookie和Header
  - 优点：兼容性最佳
  - 缺点：略显冗余

### 前端使用示例（header模式）

```javascript
// 登录获取令牌
async function login(username, password) {
  const response = await fetch('/api/auth/login', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ username, password })
  });
  
  // 从响应头获取令牌
  const token = response.headers.get('X-Access-Token');
  localStorage.setItem('token', token);
  
  return token;
}

// 访问受保护资源
async function fetchProtectedResource() {
  const token = localStorage.getItem('token');
  const response = await fetch('/api/protected', {
    headers: { 'Authorization': `Bearer ${token}` }
  });
  return await response.json();
}
```

## CORS配置说明

当你在跨域环境中使用SoulSeal时，需正确配置CORS：

```python
app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://localhost:3000"],
    allow_credentials=True,  # 允许携带凭证（Cookie）
    allow_methods=["*"],
    allow_headers=["*"],
    expose_headers=["X-Access-Token"]  # 暴露令牌头（header模式必需）
)
```

## 最佳实践

1. **生产环境配置**：
   - 使用强健的JWT密钥
   - 启用HTTPS
   - 合理设置令牌过期时间

2. **令牌存储方式选择**：
   - 单域名应用：使用`cookie`模式
   - 前后端分离：使用`header`模式
   - 混合环境：使用`both`模式

3. **微服务架构**：
   - 部署一个中心SoulSeal服务
   - 各微服务使用TokenSDK远程模式验证令牌

## 令牌管理集成指南

SoulSeal采用标准的JWT令牌认证机制，提供完整的令牌生命周期管理功能。以下是集成指南：

### 令牌流程概述

1. **获取令牌**：用户登录时获取访问令牌和刷新令牌
2. **使用令牌**：将访问令牌附加到API请求中
3. **令牌续订**：在访问令牌即将过期前主动续订
4. **令牌刷新**：在访问令牌过期后使用刷新令牌获取新的访问令牌
5. **令牌撤销**：用户注销时撤销令牌

### 客户端集成最佳实践

#### 令牌存储

- **Cookie模式**：系统默认使用HTTP-only Cookie存储令牌，客户端无需额外处理
- **Header模式**：若使用Header模式，客户端需要自行存储令牌（localStorage或其他安全方式）

#### 令牌使用

每个API请求需要包含有效的访问令牌，通过以下方式之一：

```javascript
// 使用Cookie (默认方式，无需额外代码)

// 或使用Authorization头
fetch('/api/protected', {
  headers: {
    'Authorization': `Bearer ${accessToken}`
  }
})

// 或作为URL参数
fetch('/api/protected?access_token=yourTokenHere')
```

#### 处理令牌过期

客户端应实现以下令牌管理策略：

1. **主动续订**：监控令牌有效期，在过期前调用续订API
   ```javascript
   // 示例：检查令牌是否即将过期（例如剩余10分钟）
   if (tokenExpiresIn < 10 * 60) {
     // 调用续订API
     const response = await fetch('/api/auth/renew-token', {
       method: 'POST',
       credentials: 'include' // 包含Cookie
     });
     // 系统会自动设置新的Cookie或返回新令牌
   }
   ```

2. **过期后刷新**：捕获401错误，尝试刷新令牌
   ```javascript
   async function apiRequest(url, options = {}) {
     try {
       const response = await fetch(url, options);
       if (response.ok) return response.json();
       
       if (response.status === 401) {
         // 尝试刷新令牌
         const refreshResult = await fetch('/api/auth/refresh-token', {
           method: 'POST',
           credentials: 'include'
         });
         
         if (refreshResult.ok) {
           // 令牌已刷新，重试原始请求
           return apiRequest(url, options);
         } else {
           // 刷新失败，需要重新登录
           redirectToLogin();
         }
       }
       
       throw new Error(`API error: ${response.status}`);
     } catch (error) {
       console.error('Request failed:', error);
       throw error;
     }
   }
   ```

### API端点

| 端点 | 方法 | 描述 | 需要认证 |
|------|------|------|----------|
| `/api/auth/login` | POST | 登录并获取令牌 | 否 |
| `/api/auth/renew-token` | POST | 续订未过期的访问令牌 | 是 |
| `/api/auth/refresh-token` | POST | 使用刷新令牌获取新的访问令牌 | 是(过期的令牌) |
| `/api/auth/logout` | POST | 撤销当前设备的令牌 | 是 |

### 安全注意事项

1. 访问令牌的有效期较短（默认30分钟），刷新令牌有效期较长（默认7天）
2. 刷新令牌存储在服务器端，不会暴露给客户端
3. 注销时会同时撤销访问令牌和刷新令牌
4. 令牌撤销后会被加入黑名单，即使未过期也无法使用

通过正确实现以上策略，客户端可以提供流畅的用户体验，同时确保系统安全性。

