# 使用统一认证登录你的应用 · 接入指引

本文面向：**要在自有网站或 App 中提供「使用统一认证账号登录」** 的产品与研发。完成接入后，用户会跳转到统一认证站完成登录与授权，再回到你的产品。

若你只需在**统一认证站自己的登录页**上增加 GitHub、Google 等图标，请改用站内文档 **[接上游 IdP · 配置与接入](/docs/upstream-idp-integration)**，流程与本文不同。

---

## 工作原理（授权码模式）

统一认证服务作为 **OAuth 2.0 授权服务器**。典型步骤如下：

1. 用户在你的产品点击登录，浏览器打开统一认证的**授权页**。
2. 用户在统一认证站登录（若未登录）并同意后，浏览器带着**一次性授权码 `code`** 回到你预先登记的 **回调地址**。
3. 你的**服务端**用 `code` 调用 **换票接口** 得到 `access_token`，再通过 **用户信息接口** 读取用户资料。  
   **请勿**在网页前端保存或传输 `client_secret`。

## 一、登记应用

使用统一认证站账号登录后，进入 **OAuth 应用管理**，创建应用并填写：

| 项目 | 说明 |
|------|------|
| 回调地址 | 用户授权结束后浏览器会跳回的 URL，须与代码里使用的地址**完全一致**（协议、域名、路径、端口、末尾斜杠等）。可添加多个。 |
| 权限范围（Scope） | 默认一般为 `openid profile email`，表示可获取标识与基础资料。 |
| 客户端类型 | 无法安全保存密钥的纯前端场景可选择「公开客户端」；涉及密钥的请求仍应经过你的服务端。 |

创建后请记录 **Client ID**；非公开客户端还会获得 **Client Secret**，请当作密码保管。

## 二、打开授权页

在浏览器中访问（将根地址换成你实际使用的认证服务地址）：

```http
GET {{BASE_URL}}/api/oauth/authorize
```

常用查询参数：

| 参数 | 必填 | 说明 |
|------|------|------|
| `client_id` | 是 | 应用管理中的 Client ID |
| `redirect_uri` | 是 | 须已登记在应用中 |
| `response_type` | 是 | 固定为 `code` |
| `scope` | 否 | 默认 `openid profile email` |
| `state` | 强烈建议 | 随机字符串，回调时原样带回，用于防止伪造回调 |
| `code_challenge`、`code_challenge_method` | 否 | 用于 PKCE；当前服务对换票时的校验策略以线上版本为准，详见 **[API 参考](/docs/idp-oauth2-api)** |

若参数不合法或回调地址未登记，用户通常会被引导至统一认证站的**错误说明页**，而不是返回 JSON。

授权成功后，用户浏览器会以 **GET** 跳转到：

```text
你的 redirect_uri?code=<授权码>&state=<你传入的 state>
```

授权码有效期较短（约数分钟级）、**仅可使用一次**。

## 三、服务端换取访问令牌

你的服务端向换票地址发起 **POST**（`Content-Type: application/x-www-form-urlencoded`）：

```http
POST {{BASE_URL}}/api/oauth/token
```

必填字段包括：`grant_type=authorization_code`、`code`、`client_id`、`redirect_uri`；非公开客户端还需 `client_secret`。字段说明、错误码与可选传参方式见 **[API 参考](/docs/idp-oauth2-api)**。

成功时返回标准 OAuth 2.0 JSON，包含 `access_token`、`token_type`、`expires_in`、`scope` 等（通常**没有**外层 `data` 包装）。

## 四、获取用户信息

使用上一步得到的令牌调用：

```http
GET {{BASE_URL}}/api/auth/me
Authorization: Bearer <access_token>
```

响应为 JSON，用户字段一般在 `data` 对象中（具体字段以实际返回为准）。

## 五、用户没有邮箱时的补充步骤（由统一认证站托管）

部分场景下，用户通过统一认证站内部流程登录后需要**补绑邮箱**，此时由**统一认证站页面**引导用户完成验证。该步骤在**用户浏览器**内完成，使用统一认证站下发的临时会话 Cookie，**不是你的应用后端需要单独对接的开放接口清单**。

你的应用侧仍按上文完成 **authorize → token → 用户信息** 即可。若需了解相关 HTTP 路径（供联调或排错），见 **[API 参考](/docs/idp-oauth2-api)** 中绑定邮箱相关小节。

## 权限范围（Scope）说明

| 取值 | 含义 |
|------|------|
| `openid` | 用户标识 |
| `profile` | 昵称、头像等资料 |
| `email` | 邮箱 |

授权时请求的 scope 不应超出应用登记时允许的范围。

## 安全与常见问题提示

- 为每次授权请求生成并校验 **state**。
- **redirect_uri** 在「打开授权页」与「换票」两次请求中必须一致，且与登记信息一致。
- **client_secret** 仅存在于服务端；泄露后应在应用管理中轮换或停用应用。
- 应用被停用后，授权与换票将失败。

## 流程简图

```text
用户在你的产品点击登录
  → 浏览器打开 {{BASE_URL}}/api/oauth/authorize?...
  → 在统一认证站登录并同意
  → 浏览器回到你的 redirect_uri?code=...&state=...
你的服务端 POST /api/oauth/token → 获得 access_token
  → GET /api/auth/me（Bearer）→ 用户资料
```
