通过 OpenID Connect 实现单点登录
现在,用户可以用你身份提供商(IdP)里已有的账号登录 Specivo。Specivo 是一个 OpenID Connect 客户端,因此 Keycloak、authentik、Microsoft Entra ID 以及任何发布了发现文档(discovery document)的提供商都可以接入。在 管理 → 单点登录 中完成配置;在你添加提供商之前,单点登录(SSO)一直处于关闭状态。
我们用 Keycloak 和 authentik 做了端到端测试。Entra ID 有一页完整的配置说明。Okta、Google、Zitadel 和 Authelia 只有简短的说明,没有逐屏验证过,所以请对照提供商的最新文档核对每一项设置,并使用 Specivo 内置的连接测试。单点登录指南解释了每一项设置,另有 Keycloak、authentik、Microsoft Entra ID 和其他提供商的专门页面。
你能得到什么:
- 同时接入多个提供商。每个提供商在登录页上有自己的按钮,有连接测试,客户端密钥加密存储。密钥也可以改为从
SPECIVO_SSO_SECRET_*环境变量读取。 - 首次登录自动建号。Specivo 可以在用户第一次登录时创建账户。已有账户的用户可以在 个人资料 → 已关联的账户 中关联,你也可以允许按已验证邮箱自动关联。这三项默认都是关闭的。
- 用户组映射。身份提供商中的用户组可以映射到 Specivo 的用户组和管理员标志。每个提供商还可以要求用户必须属于特定用户组,并把登录限制在一组邮箱域名内。
- 退出登录联动提供商。从 Specivo 退出登录时,可以同时在提供商处退出。开启后端通道登出(back-channel logout)后,在提供商处结束的会话也会在 Specivo 中结束。
- 登录页选项。显示提供商按钮、隐藏密码表单、直接跳转到某一个提供商,或者只为管理员保留密码登录。
- 审计事件覆盖登录、账户关联、用户组变更、退出登录和提供商变更。偏好设置 → 安全 下新增了会话列表,显示每个会话的登录方式。
在底层,Specivo 对每个提供商都使用带 PKCE(S256)、state 和 nonce 的授权码流程。服务账户(AI 智能体使用的那类账户)永远不能通过单点登录登录,API 密钥也不受影响。
本地账户照常可用。如果某项登录页设置把你自己锁在了门外,在登录 URL 后加 ?local=1,或者使用 SSO_FORCE_LOCAL_LOGIN 设置,就能重新进入。测试期间请保留一个有密码的管理员账户。
单点登录只支持 OpenID Connect。不支持 SAML,也没有 SCIM 或 LDAP 目录同步:用户在第一次登录时才会出现。指南中有一节讲如何在人员离职时移除访问权限。
停用用户
管理员现在可以在用户页面上停用和重新启用用户。停用会结束该用户的所有会话,并关闭其 API 密钥。重新启用不会自动重新打开这些密钥,由你决定恢复哪些。
退出登录、密码和 API 密钥
会话相关的几处行为有了变化,大多是改进,但如果你有脚本对接 Specivo,有几项需要留意。
- 退出登录改为表单。从书签或链接打开
/logout/时,现在会先询问“退出登录?”。POST /api/v1/auth/logout/返回200并附带end_session_url,而不再是204。除非会话来自支持远端登出的提供商,否则该值为null。 - 退出登录真正退出。以前,服务端会话和访问令牌会一直有效到过期。现在两者同时结束。
- 重置密码会结束该账户的所有会话,无论是通过邮件、由管理员操作还是在命令行完成。只通过单点登录登录的用户无法通过邮件重置密码。
- 管理员 API 密钥的权限收窄。以下操作会被拒绝并返回
403:重置密码、解锁或重新启用用户、创建用户或管理员、为其他用户签发密钥、更改单点登录设置。创建服务账户仍然允许。原先用密钥执行上述操作的自动化脚本,必须改为以已登录的管理员身份运行。
代理之后的客户端地址
现在,只有当请求经由 TRUSTED_PROXIES 中列出的代理进入时,Specivo 才会从 X-Forwarded-For 读取客户端地址。TRUSTED_PROXY_HOPS 指定链路上串联了多少层代理,默认为 1。这也修复了内置 nginx 之后的所有客户端共用同一个限流桶的问题,审计日志中显示的也将是真实地址。内置 nginx 的访问日志不再记录查询字符串,因为其中可能包含单点登录流程中的 code 和 state。
安全修复
- 只携带刷新 Cookie 的请求会跳过 CSRF 检查。
- 令牌刷新可能与会话撤销产生竞争,导致会话被保留。
- 退出登录后,服务端会话和访问令牌会一直有效到过期。见上文。
其他小改动
- 从用户表中删除了未使用的
github_id和google_id列。
升级时要做什么
先备份数据库和数据目录。升级会在启动时应用三个迁移(0041 到 0043)。保持原有行为无需任何配置,已登录的用户也会保持登录状态。
- 内置部署栈新增了一个
proxy网络。请使用新的docker-compose.yml:nginx 在该网络上使用固定地址,这样 Specivo 就能只信任这一个地址。如果docker compose up -d因“Pool overlaps”而停止,在.env中把SPECIVO_PROXY_SUBNET和SPECIVO_NGINX_IP设为一个空闲的网段和地址。 - 使用自己的 Compose 文件或 nginx 配置?用同样的方式添加该网络,或者把
TRUSTED_PROXIES设为你的代理地址。TRUSTED_PROXIES为空时,代理之后的所有人都共用一个地址。如果内置 nginx 前面还有另一层代理,设置TRUSTED_PROXY_HOPS=2。自定义的nginx/default.conf必须保留proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;。 - 如果要开启单点登录,先设置
APP_URL。重定向地址和登出地址都由它生成。 - 轮换
SECRET_KEY现在意味着还要重新输入 SSO 客户端密钥,因为这些密钥是用由它派生的密钥加密的。请把.env.local和数据库转储一起备份。 - 期望退出登录返回
204的脚本必须改为接受200;使用管理员 API 密钥执行上述操作的自动化也必须调整。
完整细节见升级指南。
如何获取
运行 docker pull specivo/specivo:0.10.0 拉取 Docker 镜像。无法访问互联网的服务器可以使用 GitHub Release 中附带的离线包。安装和升级步骤见用户指南。