Files
SnapOtter/apps/docs/zh-CN/guide/oidc.md
T
SnapOtterandGitHub 4963ab3bbd feat(docs-i18n): translate all documentation into 20 languages
All 181 docs markdown files translated into 20 languages (apps/docs/<locale>/**). Companion to the i18n code PR; admin-merged because the file count exceeds GitHub's per-PR CI trigger limit. Validated by pnpm i18n:check (all surfaces, 0 stale/missing) and a clean all-locale docs build.
2026-07-11 13:52:47 +08:00

171 lines
7.9 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.
---
description: "使用 OpenID Connect 设置单点登录。提供 Keycloak、Authentik、Google 及其他 OIDC 提供商的分步指南。"
i18n_source_hash: 4296343b3cc5
i18n_provenance: human
i18n_output_hash: 57678911503c
---
# OIDC / 单点登录 {#oidc-single-sign-on}
SnapOtter 支持使用 OpenID Connect(OIDC)进行单点登录。用户可以使用 Keycloak、Authentik 或 Google 等外部身份提供商登录,作为本地用户名/密码认证的替代方案(或与之并存)。
::: tip 另请参阅
[SAML SSO](/zh-CN/guide/saml) | [SCIM 预置](/zh-CN/guide/scim) | [用户、角色与权限](/zh-CN/guide/users-roles)
:::
## 快速开始 {#quick-start}
将这些环境变量添加到你的 `docker-compose.yml` 中:
```yaml
services:
SnapOtter:
image: snapotter/snapotter:latest
environment:
EXTERNAL_URL: "https://photos.example.com"
OIDC_ENABLED: "true"
OIDC_ISSUER_URL: "https://auth.example.com/realms/myrealm"
OIDC_CLIENT_ID: "snapotter"
OIDC_CLIENT_SECRET: "your-secret-here"
```
你的提供商的重定向 URI 始终为:
```
${EXTERNAL_URL}/api/auth/oidc/callback
```
例如,如果 `EXTERNAL_URL``https://photos.example.com`,请将你的提供商的重定向 URI 配置为 `https://photos.example.com/api/auth/oidc/callback`
## 配置参考 {#configuration-reference}
| 变量 | 默认值 | 说明 |
|---|---|---|
| `OIDC_ENABLED` | `false` | 启用 OIDC 登录。登录页面上会出现一个“使用 SSO 登录”按钮。 |
| `OIDC_ISSUER_URL` | | 提供商的 issuer URL。必须支持 OIDC 发现(`/.well-known/openid-configuration`)。 |
| `OIDC_CLIENT_ID` | | 在你的提供商处注册的 OAuth 客户端 ID。 |
| `OIDC_CLIENT_SECRET` | | OAuth 客户端密钥。 |
| `OIDC_SCOPES` | `openid profile email` | 要请求的作用域列表,以空格分隔。 |
| `OIDC_AUTO_CREATE_USERS` | `true` | 在首次 OIDC 登录时自动创建本地用户账户。 |
| `OIDC_DEFAULT_ROLE` | `user` | 分配给自动创建的 OIDC 用户的角色。为 `admin``editor``user` 之一。 |
| `OIDC_AUTO_LINK_USERS` | `false` | 如果电子邮件地址匹配,则将 OIDC 身份链接到现有的本地用户。 |
| `OIDC_PROVIDER_NAME` | | 显示在登录按钮上的名称(例如“Keycloak”、“Google”)。如果为空,按钮显示“SSO”。 |
| `OIDC_CLOCK_TOLERANCE` | `30` | 令牌验证时允许的时钟偏差容差(秒)。 |
| `OIDC_USERNAME_CLAIM` | `preferred_username` | 用作新账户用户名的 ID 令牌声明。 |
| `EXTERNAL_URL` | | SnapOtter 可访问的公共 URL。OIDC 构建正确的重定向 URI 时需要此项。 |
| `COOKIE_SECRET` | 自动生成 | 用于签名会话 cookie 的密钥。运行多个副本时请显式设置此项。 |
## 提供商指南 {#provider-guides}
### Keycloak {#keycloak}
1. 创建一个新 realm(或使用现有的 realm)。
2. 进入 **Clients** 并创建一个新 client
- **Client ID**`snapotter`
- **Client authentication**On(保密型)
- **Authentication flow**Standard flow(授权码)
3. 在该 client 的 **Settings** 选项卡下,将 **Valid redirect URIs** 设置为你的回调 URL(例如 `https://photos.example.com/api/auth/oidc/callback`)。
4.**Credentials** 选项卡复制 **Client secret**
5.`OIDC_ISSUER_URL` 设置为 `https://keycloak.example.com/realms/your-realm`
### Authentik {#authentik}
1. 在管理界面中,进入 **Applications > Providers** 并创建一个新的 **OAuth2/OpenID Provider**
- **Client type**Confidential
- **Redirect URIs**:你的回调 URL
- **Signing key**:选择现有密钥或创建一个
2. 创建一个 **Application** 并将其链接到该 provider。
3. 从 provider 设置中复制 **Client ID****Client Secret**
4.`OIDC_ISSUER_URL` 设置为 `https://authentik.example.com/application/o/snapotter/`(末尾的斜杠很重要)。
### Google {#google}
1. 进入 [Google Cloud Console](https://console.cloud.google.com/)。
2. 创建一个项目(或选择现有项目)。
3. 导航到 **APIs & Services > OAuth consent screen** 并进行配置。
4. 进入 **APIs & Services > Credentials** 并创建一个 **OAuth 2.0 Client ID**
- **Application type**Web application
- **Authorized redirect URIs**:你的回调 URL
5. 复制 **Client ID****Client secret**
6.`OIDC_ISSUER_URL` 设置为 `https://accounts.google.com`
7.`OIDC_USERNAME_CLAIM` 设置为 `email`Google 不提供 `preferred_username`)。
## 用户预置 {#user-provisioning}
### 自动创建 {#auto-create}
`OIDC_AUTO_CREATE_USERS``true`(默认)时,会在某人首次通过 OIDC 登录时创建一个本地用户账户。用户名取自 `OIDC_USERNAME_CLAIM` 指定的声明,角色设置为 `OIDC_DEFAULT_ROLE`
如果发生用户名冲突,会追加一个数字后缀(例如 `jane` 变为 `jane_2`)。
### 自动链接 {#auto-link}
`OIDC_AUTO_LINK_USERS``true` 时,如果电子邮件地址匹配,SnapOtter 会将 OIDC 身份链接到现有的本地账户。当你已预先创建用户账户,并希望他们在不丢失数据的情况下开始使用 SSO 时,这很有用。
::: warning
只有在你信任 OIDC 提供商会验证电子邮件地址的情况下,才启用自动链接。未经验证的电子邮件可能会让某人接管另一个用户的账户。
:::
### 禁用本地登录 {#disabling-local-login}
OIDC 不会禁用本地用户名/密码登录。两种方式都仍然可用。如果 OIDC 提供商无法访问,管理员仍可使用本地凭据登录。
## 自签名证书 {#self-signed-certificates}
如果你的 OIDC 提供商使用自签名或私有 CA 证书,请将 CA 证书包挂载到容器中,并将 `NODE_EXTRA_CA_CERTS` 指向它:
```yaml
services:
SnapOtter:
image: snapotter/snapotter:latest
volumes:
- ./my-ca.pem:/etc/ssl/certs/custom-ca.pem:ro
environment:
NODE_EXTRA_CA_CERTS: /etc/ssl/certs/custom-ca.pem
OIDC_ENABLED: "true"
OIDC_ISSUER_URL: "https://auth.internal.example.com/realms/myrealm"
OIDC_CLIENT_ID: "snapotter"
OIDC_CLIENT_SECRET: "your-secret-here"
```
::: danger
请勿设置 `NODE_TLS_REJECT_UNAUTHORIZED=0`。这会禁用所有 TLS 验证,存在安全风险。
:::
## 故障排查 {#troubleshooting}
### 重定向 URI 不匹配 {#redirect-uri-mismatch}
最常见的错误。检查你的提供商所期望的内容与 SnapOtter 发送的内容之间是否存在以下差异:
- `http``https` 之间,scheme 必须完全一致
- 末尾斜杠,有些提供商对此很严格
- 端口号,如果是非标准端口,请包含端口
- 路径,必须是 `/api/auth/oidc/callback`
请再次核对 `EXTERNAL_URL`。它必须与用户在浏览器中输入的 URL 一致。
### UNABLE_TO_VERIFY_LEAF_SIGNATURE {#unable-to-verify-leaf-signature}
OIDC 提供商使用了 Node.js 不信任的证书。请参阅上文的[自签名证书](#self-signed-certificates)。
### 时钟偏差错误 {#clock-skew-errors}
如果你的服务器时钟与 OIDC 提供商时钟不同步,令牌验证可能会失败。增大 `OIDC_CLOCK_TOLERANCE`(默认为 30 秒)。更好的办法是在两台机器上都运行 NTP。
### “OIDC 提供商无法访问” {#oidc-provider-unreachable}
SnapOtter 会在启动时和登录期间获取提供商的发现文档。请检查:
- 从 Docker 容器内部进行的 DNS 解析(`docker exec snapotter nslookup auth.example.com`
- 容器与提供商之间的防火墙规则
- `OIDC_ISSUER_URL` 的值,它必须能从服务器访问,而不仅仅是从你的浏览器访问
### 缺少声明 {#missing-claims}
如果登录后用户名或电子邮件为空,你的提供商可能没有返回预期的声明。请验证:
-`OIDC_SCOPES` 中配置的作用域包含 `profile``email`
- 提供商已配置为在 ID 令牌中包含 `OIDC_USERNAME_CLAIM` 指定的声明
- 有些提供商需要显式的 mapper/scope 配置才能释放声明