This page was machine-translated. Spotted a mistake?Help improve it.
Skip to content

OIDC / 单点登录

SnapOtter 支持使用 OpenID Connect(OIDC)进行单点登录。用户可以使用 Keycloak、Authentik 或 Google 等外部身份提供商登录,作为本地用户名/密码认证的替代方案(或与之并存)。

快速开始

将这些环境变量添加到你的 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_URLhttps://photos.example.com,请将你的提供商的重定向 URI 配置为 https://photos.example.com/api/auth/oidc/callback

配置参考

变量默认值说明
OIDC_ENABLEDfalse启用 OIDC 登录。登录页面上会出现一个“使用 SSO 登录”按钮。
OIDC_ISSUER_URL提供商的 issuer URL。必须支持 OIDC 发现(/.well-known/openid-configuration)。
OIDC_CLIENT_ID在你的提供商处注册的 OAuth 客户端 ID。
OIDC_CLIENT_SECRETOAuth 客户端密钥。
OIDC_SCOPESopenid profile email要请求的作用域列表,以空格分隔。
OIDC_AUTO_CREATE_USERStrue在首次 OIDC 登录时自动创建本地用户账户。
OIDC_DEFAULT_ROLEuser分配给自动创建的 OIDC 用户的角色。为 admineditoruser 之一。
OIDC_AUTO_LINK_USERSfalse如果电子邮件地址匹配,则将 OIDC 身份链接到现有的本地用户。
OIDC_PROVIDER_NAME显示在登录按钮上的名称(例如“Keycloak”、“Google”)。如果为空,按钮显示“SSO”。
OIDC_CLOCK_TOLERANCE30令牌验证时允许的时钟偏差容差(秒)。
OIDC_USERNAME_CLAIMpreferred_username用作新账户用户名的 ID 令牌声明。
EXTERNAL_URLSnapOtter 可访问的公共 URL。OIDC 构建正确的重定向 URI 时需要此项。
COOKIE_SECRET自动生成用于签名会话 cookie 的密钥。运行多个副本时请显式设置此项。

提供商指南

Keycloak

  1. 创建一个新 realm(或使用现有的 realm)。
  2. 进入 Clients 并创建一个新 client:
    • Client IDsnapotter
    • 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

  1. 在管理界面中,进入 Applications > Providers 并创建一个新的 OAuth2/OpenID Provider
    • Client type:Confidential
    • Redirect URIs:你的回调 URL
    • Signing key:选择现有密钥或创建一个
  2. 创建一个 Application 并将其链接到该 provider。
  3. 从 provider 设置中复制 Client IDClient Secret
  4. OIDC_ISSUER_URL 设置为 https://authentik.example.com/application/o/snapotter/(末尾的斜杠很重要)。

Google

  1. 进入 Google Cloud Console
  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 IDClient secret
  6. OIDC_ISSUER_URL 设置为 https://accounts.google.com
  7. OIDC_USERNAME_CLAIM 设置为 email(Google 不提供 preferred_username)。

用户预置

自动创建

OIDC_AUTO_CREATE_USERStrue(默认)时,会在某人首次通过 OIDC 登录时创建一个本地用户账户。用户名取自 OIDC_USERNAME_CLAIM 指定的声明,角色设置为 OIDC_DEFAULT_ROLE

如果发生用户名冲突,会追加一个数字后缀(例如 jane 变为 jane_2)。

OIDC_AUTO_LINK_USERStrue 时,如果电子邮件地址匹配,SnapOtter 会将 OIDC 身份链接到现有的本地账户。当你已预先创建用户账户,并希望他们在不丢失数据的情况下开始使用 SSO 时,这很有用。

WARNING

只有在你信任 OIDC 提供商会验证电子邮件地址的情况下,才启用自动链接。未经验证的电子邮件可能会让某人接管另一个用户的账户。

禁用本地登录

OIDC 不会禁用本地用户名/密码登录。两种方式都仍然可用。如果 OIDC 提供商无法访问,管理员仍可使用本地凭据登录。

自签名证书

如果你的 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 验证,存在安全风险。

故障排查

重定向 URI 不匹配

最常见的错误。检查你的提供商所期望的内容与 SnapOtter 发送的内容之间是否存在以下差异:

  • httphttps 之间,scheme 必须完全一致
  • 末尾斜杠,有些提供商对此很严格
  • 端口号,如果是非标准端口,请包含端口
  • 路径,必须是 /api/auth/oidc/callback

请再次核对 EXTERNAL_URL。它必须与用户在浏览器中输入的 URL 一致。

UNABLE_TO_VERIFY_LEAF_SIGNATURE

OIDC 提供商使用了 Node.js 不信任的证书。请参阅上文的自签名证书

时钟偏差错误

如果你的服务器时钟与 OIDC 提供商时钟不同步,令牌验证可能会失败。增大 OIDC_CLOCK_TOLERANCE(默认为 30 秒)。更好的办法是在两台机器上都运行 NTP。

“OIDC 提供商无法访问”

SnapOtter 会在启动时和登录期间获取提供商的发现文档。请检查:

  • 从 Docker 容器内部进行的 DNS 解析(docker exec snapotter nslookup auth.example.com
  • 容器与提供商之间的防火墙规则
  • OIDC_ISSUER_URL 的值,它必须能从服务器访问,而不仅仅是从你的浏览器访问

缺少声明

如果登录后用户名或电子邮件为空,你的提供商可能没有返回预期的声明。请验证:

  • OIDC_SCOPES 中配置的作用域包含 profileemail
  • 提供商已配置为在 ID 令牌中包含 OIDC_USERNAME_CLAIM 指定的声明
  • 有些提供商需要显式的 mapper/scope 配置才能释放声明