# 统一认证平台 - 简易认证 (Simple Auth) 集成指南 ## 1. 概述 本指南适用于需要使用自定义登录页面(而非跳转到认证中心标准页面),并通过后端 API 直接进行用户认证的场景。 **Base URL**: `http://localhost:8000/api/v1/simple` (开发环境) ## 2. 核心流程 1. **用户输入**: 用户在客户端输入账号密码。 2. **签名**: 客户端/后端生成签名 (Sign)。 3. **登录**: POST `/login` (账号+密码+签名) -> 获取 `Ticket`。 4. **验证**: POST `/validate` (Ticket+签名) -> 获取用户信息。 ## 3. 安全警告 - **App Secret** 严禁泄露给前端浏览器。 - 建议所有涉及 Secret 的签名计算都在**后端**完成。 ## 4. 签名算法 (Signature) 所有接口(除部分公开接口外)都需要校验签名。 **步骤**: 1. **准备参数**: 收集所有请求参数(**排除 `sign` 本身**)。 2. **排序**: 按照参数名(key)的 ASCII 码从小到大排序。 3. **拼接**: 将排序后的参数拼接成 `key1=value1&key2=value2...` 格式。 4. **计算 HMAC**: 使用 `App Secret` 作为密钥,对拼接字符串进行 **HMAC-SHA256** 计算。 5. **Hex 编码**: 将结果转换为十六进制字符串。 ### Python 示例 ```python import hmac import hashlib def generate_signature(secret: str, params: dict) -> str: data = {k: v for k, v in params.items() if k != "sign" and v is not None} sorted_keys = sorted(data.keys()) query_string = "&".join([f"{k}={data[k]}" for k in sorted_keys]) signature = hmac.new( secret.encode('utf-8'), query_string.encode('utf-8'), hashlib.sha256 ).hexdigest() return signature ``` ## 5. 接口定义 ### 5.1 密码登录 (Login) 获取临时票据 (Ticket)。 - **URL**: `POST /login` - **Content-Type**: `application/json` **Request Body**: | Field | Type | Required | Description | |---|---|---|---| | `app_id` | string | Yes | 应用 ID | | `identifier` | string | Yes | 用户标识(手机号、用户名或邮箱) | | `password` | string | Yes | 明文密码 | | `timestamp` | int | Yes | 当前时间戳 (秒) | | `sign` | string | Yes | 签名 | **Response (200)**: ```json { "ticket": "TICKET-7f8e9d0a-..." } ``` ### 5.2 验证票据 (Validate) 解析票据获取用户信息。 - **URL**: `POST /validate` - **Content-Type**: `application/json` **Request Body**: | Field | Type | Required | Description | |---|---|---|---| | `app_id` | string | Yes | 应用 ID | | `ticket` | string | Yes | 上一步获取的票据 | | `timestamp` | int | Yes | 当前时间戳 | | `sign` | string | Yes | 签名 (参数变化需重新计算) | **Response (200)**: ```json { "valid": true, "user_id": 1001, "mobile": "13800138000", "mapped_key": "user_zhangsan", // 第三方映射ID "mapped_email": "zhangsan@example.com" } ``` **Response (Invalid)**: ```json { "valid": false } ```