Search K
SAML SSO
SnapOtter 支持使用 SAML 2.0 进行单点登录。用户可以通过外部身份提供商(Okta、Azure AD / Entra ID、Google Workspace 或任何标准的 SAML 2.0 IdP)登录,作为本地用户名/密码认证的替代方案。
企业功能
SAML SSO 需要具备 saml_sso 功能的 团队 或 企业 许可证。如果设置了 SAML_ENABLED=true 但没有有效的许可证,SAML 路由会被静默跳过,并记录一条警告。
前置条件
- 一个可通过公共 URL 访问的运行中的 SnapOtter 实例
- 将
EXTERNAL_URL设置为该公共 URL(例如https://photos.example.com) - 具备
saml_sso功能的团队或企业许可证密钥 - 你的 SAML 身份提供商的管理员访问权限
快速开始
将这些环境变量添加到你的 docker-compose.yml 中:
yaml
services:
snapotter:
image: snapotter/snapotter:latest
environment:
EXTERNAL_URL: "https://photos.example.com"
SNAPOTTER_LICENSE_KEY: "your-license-key"
SAML_ENABLED: "true"
SAML_IDP_SSO_URL: "https://idp.example.com/sso/saml"
SAML_IDP_CERTIFICATE: |
MIICpDCCAYwCCQDU+pQ4pHgSpDANBgkqhkiG9w0BAQsFADAUMRIw
...your IdP's signing certificate in PEM format...
EAYHKoZIzj0CAQYFK4EEACIDYgAE重启容器。登录页面上会出现一个“使用 SAML 登录”按钮(或由 SAML_PROVIDER_NAME 设置的标签)。
配置参考
| 变量 | 默认值 | 说明 |
|---|---|---|
SAML_ENABLED | false | 启用 SAML 登录。 |
SAML_IDP_SSO_URL | IdP 的 SSO 端点 URL。启用 SAML 时必填。 | |
SAML_IDP_CERTIFICATE | IdP 的 PEM 格式 X.509 签名证书(证书文本本身,而非文件路径)。启用 SAML 时必填。 | |
EXTERNAL_URL | SnapOtter 可访问的公共 URL。启用 SAML 时必填。 | |
SAML_ENTITY_ID | ${EXTERNAL_URL}/api/auth/saml/metadata | 发送给 IdP 的 SP Entity ID / Audience URI。 |
SAML_CALLBACK_URL | ${EXTERNAL_URL}/api/auth/saml/callback | 断言消费者服务(ACS)URL。 |
SAML_AUTO_CREATE_USERS | true | 在首次 SAML 登录时自动创建本地用户账户。 |
SAML_AUTO_LINK_USERS | false | 如果电子邮件地址匹配,则将 SAML 身份链接到现有的本地用户。 |
SAML_DEFAULT_ROLE | user | 分配给自动创建的 SAML 用户的角色。为 admin、editor 或 user 之一。 |
SAML_PROVIDER_NAME | 前端 SAML 登录按钮的显示标签(例如“Okta”、“Azure AD”)。如果为空,按钮显示“SAML”。 | |
SAML_USERNAME_ATTRIBUTE | 用作用户名的 SAML 断言属性。如果为空,则回退为电子邮件的本地部分,然后是 NameID。 | |
SAML_EMAIL_ATTRIBUTE | email | 用作用户电子邮件地址的 SAML 断言属性。 |
如果 SAML_ENABLED=true 而三个必填变量(SAML_IDP_SSO_URL、SAML_IDP_CERTIFICATE、EXTERNAL_URL)中有任何一个缺失,服务器将拒绝启动。
安全说明
wantAuthnResponseSigned 和 wantAssertionsSigned 都被硬编码为 true。SnapOtter 会拒绝未签名或签名不当的 SAML 响应。来自受信任 IdP 的断言被视为已验证电子邮件。
仅支持 SP 发起的登录。SnapOtter 不支持 IdP 发起的(未经请求的)登录或单点登出(SLO)。登出 SnapOtter 不会将用户从 IdP 登出。
SP 元数据和 URL
你的 IdP 需要来自 SnapOtter 的三个值:
| 字段 | 值 |
|---|---|
| ACS URL(断言消费者服务) | ${EXTERNAL_URL}/api/auth/saml/callback |
| Entity ID / Audience URI | ${EXTERNAL_URL}/api/auth/saml/metadata |
| SP 元数据(XML) | GET ${EXTERNAL_URL}/api/auth/saml/metadata |
例如,如果 EXTERNAL_URL 是 https://photos.example.com:
- ACS URL:
https://photos.example.com/api/auth/saml/callback - Entity ID:
https://photos.example.com/api/auth/saml/metadata - 元数据端点:
https://photos.example.com/api/auth/saml/metadata(返回 XML)
有些 IdP 可以直接导入 SP 元数据 URL,从而自动填充 ACS URL 和 Entity ID。
提供商设置
Okta
- 在 Okta 管理控制台中,进入 Applications > Create App Integration。
- 选择 SAML 2.0 并点击 Next。
- 设置一个名称(例如“SnapOtter”)并点击 Next。
- 配置 SAML 设置:
- Single sign-on URL:你的 ACS URL(例如
https://photos.example.com/api/auth/saml/callback) - Audience URI (SP Entity ID):你的 Entity ID(例如
https://photos.example.com/api/auth/saml/metadata) - Name ID format:EmailAddress
- Application username:Email
- Single sign-on URL:你的 ACS URL(例如
- 在 Attribute Statements 下,添加
email并映射到user.email。 - 点击 Next,然后点击 Finish。
- 进入 Sign On 选项卡,点击 View SAML setup instructions,并复制:
- Identity Provider Single Sign-On URL 到
SAML_IDP_SSO_URL - X.509 Certificate 到
SAML_IDP_CERTIFICATE
- Identity Provider Single Sign-On URL 到
Azure AD / Entra ID
- 在 Azure 门户中,进入 Microsoft Entra ID > Enterprise applications > New application。
- 点击 Create your own application,将其命名为“SnapOtter”,并选择 Integrate any other application you don't find in the gallery。
- 进入 Single sign-on > SAML,并在 Basic SAML Configuration 部分点击 Edit:
- Identifier (Entity ID):你的 Entity ID(例如
https://photos.example.com/api/auth/saml/metadata) - Reply URL (ACS URL):你的 ACS URL(例如
https://photos.example.com/api/auth/saml/callback)
- Identifier (Entity ID):你的 Entity ID(例如
- 在 SAML Certificates 下,下载 Certificate (Base64)。
- 在 Set up SnapOtter 下,复制 Login URL。
- 将
SAML_IDP_SSO_URL设置为该 Login URL,并将SAML_IDP_CERTIFICATE设置为所下载的证书内容。 - 在 Users and groups 下将用户或组分配给该应用。
Google Workspace
- 在 Google 管理控制台中,进入 Apps > Web and mobile apps > Add app > Add custom SAML app。
- 将该应用命名为“SnapOtter”并点击 Continue。
- 在 Google Identity Provider details 页面,复制 SSO URL 并下载 Certificate。点击 Continue。
- 配置 Service Provider 详情:
- ACS URL:你的 ACS URL(例如
https://photos.example.com/api/auth/saml/callback) - Entity ID:你的 Entity ID(例如
https://photos.example.com/api/auth/saml/metadata) - Name ID format:EMAIL
- Name ID:Basic Information > Primary email
- ACS URL:你的 ACS URL(例如
- 点击 Continue,然后点击 Finish。
- 为你的组织单位将该应用设为 ON。
- 将
SAML_IDP_SSO_URL设置为步骤 3 中的 SSO URL,并将SAML_IDP_CERTIFICATE设置为所下载的证书内容。
通用 SAML 2.0 IdP
对于任何符合 SAML 2.0 的身份提供商:
- 在你的 IdP 中创建一个新的 SAML 应用/服务提供商。
- 将 ACS URL 设置为
${EXTERNAL_URL}/api/auth/saml/callback。 - 将 Entity ID / Audience 设置为
${EXTERNAL_URL}/api/auth/saml/metadata。 - 配置 IdP 在名为
email的属性中发送用户的电子邮件(或设置SAML_EMAIL_ATTRIBUTE以匹配你的 IdP 的属性名)。 - 将 IdP SSO URL 和 签名证书 复制到
SAML_IDP_SSO_URL和SAML_IDP_CERTIFICATE。
用户预置
自动创建
当 SAML_AUTO_CREATE_USERS 为 true(默认)时,会在某人首次通过 SAML 登录时创建一个本地用户账户。角色设置为 SAML_DEFAULT_ROLE。
用户名按以下顺序派生:
SAML_USERNAME_ATTRIBUTE指定的断言属性的值(如果已设置且存在)- 电子邮件地址的本地部分(
@之前的所有内容) - SAML NameID
如果发生用户名冲突,会追加一个数字后缀(例如 jane 变为 jane_2)。
自动链接
当 SAML_AUTO_LINK_USERS 为 true 时,如果电子邮件地址匹配,SnapOtter 会将 SAML 身份链接到现有的本地账户。当你已预先创建用户账户,并希望他们在不丢失数据的情况下开始使用 SSO 时,这很有用。
WARNING
只有在你信任 SAML IdP 会验证电子邮件地址的情况下,才启用自动链接。来自配置错误的 IdP 的未经验证的电子邮件可能会让某人接管另一个用户的账户。
属性映射
| SnapOtter 字段 | 来源 | 配置 |
|---|---|---|
| 电子邮件 | 断言属性 | SAML_EMAIL_ATTRIBUTE(默认:email) |
| 用户名 | 断言属性、电子邮件或 NameID | SAML_USERNAME_ATTRIBUTE(见上文派生顺序) |
| 外部 ID | NameID | 始终为 SAML NameID,不可配置 |
SSO 强制
如果你希望要求所有用户都通过 SAML(或 OIDC)登录并阻止本地密码登录,请启用 SSO 强制:
- 确保
sso_enforcement企业功能已获授权(在团队和企业方案上可用)。 - 在 Admin Settings > Security 中,打开 SSO Enforcement。
- 设置一个 应急用户名:这是唯一一个在 IdP 无法访问时仍可使用密码登录以进行紧急访问的本地账户。
当 SSO 强制处于激活状态时,任何本地登录尝试(应急用户除外)都会返回 403 错误,消息为“Local password login is disabled. Please use SSO.”
TIP
在启用 SSO 强制之前,请务必先配置一个应急用户名。否则,如果你的 IdP 宕机,你可能会被锁在 SnapOtter 之外。
将 SAML 与 OIDC 并用
SAML 和 OIDC 可以同时启用。当两者都处于激活状态时,登录页面会为每个提供商显示各自的按钮(由 SAML_PROVIDER_NAME 和 OIDC_PROVIDER_NAME 标注)。用户可以使用任一方式登录。
两个提供商各自独立地共享相同的自动创建、自动链接和 SSO 强制设置:每个都有自己的 *_AUTO_CREATE_USERS、*_AUTO_LINK_USERS 和 *_DEFAULT_ROLE 变量。
故障排查
断言验证失败
无法验证 SAML 响应签名或断言签名。请检查:
SAML_IDP_CERTIFICATE中的证书与你的 IdP 中当前的签名证书是否匹配(证书会轮换,因此请检查是否过期)- 证书是否为 PEM 格式(以
-----BEGIN CERTIFICATE-----开头) - 证书是否为完整文本,而非文件路径
- 你的 IdP 中配置的 ACS URL 和 Entity ID 是否与 SnapOtter 的值完全一致(scheme、host、port、path)
缺少属性
如果登录后用户名或电子邮件为空,你的 IdP 可能没有发送预期的属性。请检查:
- 你的 IdP 已配置为释放一个
email属性(或SAML_EMAIL_ATTRIBUTE所设置的值) - 如果使用
SAML_USERNAME_ATTRIBUTE,请验证该属性已包含在断言中 - 有些 IdP 需要显式的属性映射配置才能释放声明
时钟偏差
SAML 断言包含时间戳条件(NotBefore、NotOnOrAfter)。如果你的服务器时钟与 IdP 时钟不同步,断言验证会失败。在两台机器上都运行 NTP 以保持时钟对齐。
“SAML is enabled via env but saml_sso enterprise feature is not licensed”
当 SAML_ENABLED=true 但许可证不包含 saml_sso 功能时,服务器日志中会出现此警告。请核对你的许可证密钥和方案。saml_sso 功能在团队和企业方案上可用。
登录重定向回来并带有错误
如果点击 SAML 登录按钮后重定向回登录页面并带有错误,请查看服务器日志以了解详情。常见原因:
- 从服务器无法访问 IdP SSO URL
- IdP 拒绝了认证请求(请查看 IdP 的审计日志)
- IdP 返回了未签名的响应(SnapOtter 要求响应和断言都必须签名)
