ClouisleClouisle

配置单点登录

配置 OIDC、SAML 2.0 或 CAS 登录连接并管理 SSO 用户生命周期

登录身份源在站点设置 → 集成(/site-settings/integrations)统一管理:登录身份源、邮件、Webhook 与飞书通讯录共用同一套集成列表,但各自的能力与权限互不混用。先在站点设置 → 安全中打开全局 SSO 策略,再逐个添加登录集成。

每个登录集成的协议配置是一段 JSON,字段随类型不同;保存前先准备好身份提供商那边的回调地址、客户端凭据与证书。

前置条件:

  1. 全局 SSO 开关已开启,否则登录页不会显示任何 SSO 按钮。
  2. 操作者具备登录集成的查看或修改权限(超级管理员始终可以)。
  3. 身份提供商能访问 Clouisle 的后端公网地址,否则回调无法到达(见下一节)。

支持范围

类型用途管理位置
OAuth2、OIDC、SAML 2.0、CAS网页登录站点设置 → 集成中的登录集成对话框
邮件、Webhook通知投递各自的专用表单
飞书登录与通讯录同步飞书集成卡片(同一套应用凭据,能力分开关控制)

飞书是一个集成同时提供通讯录同步与网页登录:启用飞书集成本身不会授予登录能力,网页登录需要在同一张卡片上显式打开;关闭集成会同时停用目录同步与登录,但保留这项选择。邮件、Webhook 与飞书为单实例集成,本页只讲登录部分。

回调地址

在身份提供商后台登记的回调(重定向)地址为:

https://your-domain.com/api/v1/sso/callback/<集成名称>
  • your-domain.com 是浏览器实际访问到后端的对外地址:经反向代理时使用代理转发的对外地址;若前端代理了接口路径,则使用前端公开域名。它不是服务内部地址,也不是前端页面地址——用错会导致回调失败或跳回错误域名。
  • 按上面的格式拼出地址(域名 + 集成名称);飞书集成卡片会直接显示可复制的重定向地址。
  • <集成名称> 必须与 Clouisle 中登记的集成名称完全一致,大小写敏感,且创建后保持稳定。回调地址不匹配是 SSO 登录失败最常见的原因。

添加登录集成

在站点设置 → 集成点击添加登录集成,对话框分 Basic Info / Configuration / Attribute Mapping 三个页签。基本信息:

字段必填约束
Provider Name(集成名称)是小写字母开头,仅含小写字母、数字、-、_;最长 100;全局唯一(重名会提示名称已存在)
Protocol(类型)是OAuth2 / OIDC / SAML 2.0 / CAS
Display Name(显示名称)是列表与关联账号卡片中的名称,最长 100
Button Text(按钮文本)否登录页按钮文案,最长 50,如「使用 GitHub 继续」
Icon URL(图标)否必须是 http:// 或 https:// 开头,最长 512
Enabled(启用)—关闭后该集成不出现在登录页
Allow Signup(允许注册)—允许该集成在首次登录时新建账户
Require Approval(需要审批)—新建的账户需管理员批准后才能登录
Default Role(默认角色)否新建账户的初始全局角色;留空时回退到站点默认角色

Provider Name 与 Protocol 在创建后不可修改。命名请与身份提供商中的配置保持一致,改名等于重建集成;已有用户身份连接会保留在原集成上。

协议配置

在 Configuration 页签中填写两段 JSON:

  • Configuration JSON:协议参数,字段名必须与下表一致;拼写错误不会在保存时报错,而是在登录时暴露为配置异常。
  • Credentials JSON:客户端密钥等敏感值,例如 {"client_secret": "..."}。不要把密钥写进 Configuration。

凭据加密存储,保存后永不回显:编辑时看到的是已配置的键名,JSON 里留空表示保留原密钥。

OAuth2 / OIDC

字段必填说明
client_id是提供商颁发的 Client ID
authorization_url是授权端点
token_url是换取令牌的端点
userinfo_url是用户信息端点(登录时读取的就是它的返回体)
scopes否空格分隔的 scope,默认 openid email profile

登录使用授权码 + PKCE(S256)流程,并生成 nonce。

当前实现没有 Issuer URL 字段,也不做 ID Token 签名/JWKS 校验:用户信息一律取自 userinfo_url 的响应。因此客户端密钥是否正确、证书是否有效,只有在真正换令牌时才会暴露,见测试连接。

SAML 2.0

字段必填说明
sp_entity_id是Service Provider Entity ID(本实例标识)
idp_entity_id是IdP Entity ID
sso_url是IdP 单点登录 URL(HTTP-Redirect 绑定)
x509_cert是IdP X.509 证书,PEM 内容但不含 -----BEGIN/END CERTIFICATE----- 头尾
acs_url是ACS 地址;仅作占位/参考,运行时始终使用实际回调地址覆盖
slo_url否SP 单点登出地址
idp_slo_url否IdP 单点登出地址
name_id_format否NameID 格式,默认 urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
{
  "sp_entity_id": "clouisle",
  "idp_entity_id": "https://idp.example.com/metadata",
  "sso_url": "https://idp.example.com/sso",
  "x509_cert": "MIIC...省略...",
  "acs_url": "https://your-domain.com/api/v1/sso/callback/azure-ad"
}

开启 strict 模式,SAML 响应必须通过签名校验;IdP 与 Clouisle 的时钟偏差过大会直接判定失败。

slo_url / idp_slo_url 只会被保存,当前没有实现 SP 发起的单点登出流程——用户在 IdP 侧登出不会同步注销 Clouisle 会话。

CAS

字段必填说明
server_url是CAS 服务器基地址
version否协议版本 1 / 2 / 3,默认 3,决定校验端点(/validate、/serviceValidate、/p3/serviceValidate)
service_url否不会生效:service 参数始终使用运行时的回调地址

CAS 用户标识取自校验响应中的 <cas:user>;版本 3 还会读取 <cas:attributes> 中的属性供属性映射使用。

属性映射

Attribute Mapping 页签是一段 JSON,把提供商返回的数据映射到 Clouisle 需要的字段:

Clouisle 字段用途
email账户邮箱(必需,缺失会导致登录失败)
username用户名,重复时会自动加数字后缀
avatar_url头像地址

两种路径写法:

  • 点号路径(默认):{"email": "email", "username": "profile.name"} 读取嵌套对象。
  • JSONPath:以 $ 开头,适合数组或过滤,{"email": "$.emails[0].value"};多个匹配时取第一个。

新建集成时的默认值:

{
  "email": "email",
  "username": "name",
  "avatar_url": "picture"
}

GitHub 的返回字段与 OIDC 标准不同,需要改成 {"email": "email", "username": "login", "avatar_url": "avatar_url"}。

映射结果会与提供商原始返回字段合并,同名字段以原始值为准。也就是说映射只对「原始返回里不存在同名键」的字段生效;若提供商已返回 email,映射里的 email 会被覆盖。排查字段错位时请先查看原始响应。

最终数据里必须有非空的 email,否则新用户创建会失败并提示邮箱缺失。OIDC 的 sub/id、SAML 的 NameID、CAS 的 <cas:user> 会作为外部身份标识;标识为空同样会导致登录失败。

配置 GitHub 登录

  1. 确保外部可访问 Clouisle,并保留可用的管理员登录方式。
  2. 在站点设置 → 安全配置全局 SSO 策略:SSO 总开关、密码登录、自动创建用户、审批和邮箱匹配。
  3. 在 GitHub 的 Settings → Developer settings → OAuth Apps 创建 OAuth 应用,把回调填写为 https://your-domain.com/api/v1/sso/callback/github。
  4. 创建名称为 github 的 OAuth2 登录集成,填写显示名称、按钮文本、图标,按需打开 Allow Signup / Require Approval 并选择默认角色。
  5. 在 Configuration 中填写 Client ID、授权 URL、token URL、userinfo URL 与 scope(read:user user:email);Attribute Mapping 使用 {"email": "email", "username": "login", "avatar_url": "avatar_url"}。
  6. 在 Credentials 中填写 {"client_secret": "..."},不要写进 Configuration。保存并测试后,用独立浏览器会话完成一次真实登录;配置测试通过不代表完整登录已通过。

配置飞书登录

飞书网页登录是飞书集成上的一项可选能力,与通讯录同步共用同一套 App ID / App Secret,无需再创建一个身份源。

  1. 在飞书开发者后台把飞书卡片中显示的重定向地址(https://<backend-host>/api/v1/sso/callback/<集成名称>,例如 …/api/v1/sso/callback/feishu)加入应用的重定向 URL 白名单;该地址可直接一键复制。
  2. 为应用授予登录所需 scope:contact:user.base:readonly contact:user.email:readonly。
  3. 在站点设置 → 集成 → 飞书卡片的能力区域打开飞书登录开关,并按需填写登录按钮文案。修改登录开关属于登录集成权限,飞书卡片上的其他设置属于集成设置权限,因此操作者通常需要同时具备两者。
  4. 如果尚未配置应用凭据,在同一张卡片上填写;凭据与通讯录同步共用,密钥留空表示保留原值。保持集成处于启用状态。

成员可以在个人设置 → 账户安全的关联账号区域点击绑定飞书,把飞书身份关联到已有账号;该入口同样要等管理员启用飞书用户登录后才出现。

只有在全局 SSO 已启用、集成已启用、且飞书登录开关打开时,登录页才会展示飞书按钮。未开启该选项时,飞书只提供通讯录同步。关闭集成会同时停用两项能力,但保留该选项。

登录身份以飞书资料中的 union_id 作为外部身份标识存储;缺少 union_id 时回退为 open_id,因此在同一开发者账号内更换应用不会导致已绑定账号失效。

通讯录中没有任何邮箱的飞书账号,会使用与目录同步一致的确定性占位邮箱,使登录与同步汇聚到同一个本地账号而不是各建一个。推导该地址需要飞书 user_id,因此需要 contact:user.employee_id:readonly;缺少该 scope 时这类账号的首次登录会被拒绝,而不会创建占位身份。

测试连接

集成卡片上的测试连接按钮(Test Connection)会在服务端仅本地构造一次授权地址(使用占位回调地址),检查配置里必需的键是否齐全:

  • 成功只说明配置能构造出授权地址。
  • 它不会访问身份提供商,因此客户端密钥错误、回调地址不匹配、证书过期这类问题它都测不出来——必须用真实登录验证。

通用流程

  1. 在站点设置 → 安全中启用 SSO,并按需调整全局策略(允许密码登录、自动创建、需要审批、按邮箱匹配)。
  2. 在站点设置 → 集成添加登录集成:填写基本信息,选择协议。
  3. 在 Configuration 页签填入该协议的 JSON 配置,把密钥填进 Credentials 而不是 Configuration。
  4. 在 Attribute Mapping 页签把邮箱、用户名、头像对应到提供商字段。
  5. 保存后,把回调地址(https://your-domain.com/api/v1/sso/callback/<集成名称>)填入身份提供商的白名单/重定向地址。
  6. 用隐身窗口验证三种情况:新用户、已存在用户、错误回调。
SSO 连接配置
SSO 连接配置

用户生命周期

全局策略与集成自己的设置是或的关系,最终判定如下:

结果判定规则
关联已有账户全局开启「按邮箱匹配已有账户」(默认开启)且返回邮箱能匹配到现有用户;关联时同时确保该用户加入默认团队
新建账户全局「自动创建用户」或集成自己的「允许注册」任一开启
新建被拒全局自动创建关闭且集成允许注册也关闭
需要审批全局「新账户需要审批」或集成的「需要审批」任一开启 → 账户为待审批且不可登录
仅 SSO 登录全局关闭「允许密码登录」后,密码登录被拒绝

新建的 SSO 用户具有以下特征:

  • 没有本地密码,因此无法用密码登录。
  • 邮箱直接标记为已验证(信任提供商的邮箱)。
  • 用户名取映射出的 username;缺失时用邮箱 @ 前的部分,再缺失时用外部身份标识前 8 位加前缀;重名会自动追加数字后缀。
  • 角色取集成设置的默认角色,未设置时回退到全局默认角色;随后按默认团队设置加入团队。

升级注意事项

从旧版 SSO 提供商模型升级到统一集成模型时:升级会保留集成标识、用户身份连接与外部身份 ID,无需重新绑定账号,也无需修改身份提供方的回调地址。

升级前备份数据库,并按升级文档要求的顺序更新全部组件;不支持新旧版本混用的滚动部署。回滚必须同时恢复切换前的数据库、匹配的应用版本与加密密钥。完整的升级与回滚步骤见升级 Clouisle。

故障排除

登录页没有 SSO 按钮

  1. 检查站点设置 → 安全中的全局 SSO 开关是否打开。
  2. 检查该集成是否启用,且飞书登录开关(如使用飞书)已打开。
  3. 确认身份提供商配置的回调地址与上面的格式一致。

回调报错 / 停在同一页面

  1. 核对回调地址的对外域名与集成名称是否与配置完全一致。
  2. 确认对外地址是身份提供商可达的公网地址。
  3. 检查用户是否在授权页停留过久(登录会话有效期 10 分钟,超时需重新发起)。
  4. 查看审计日志中的 SSO 登录失败记录与错误信息。

登录成功但字段错位

  1. 按属性映射确认路径写法(点号 vs $ JSONPath)。
  2. 注意同名原始字段会覆盖映射值。
  3. GitHub 等非 OIDC 标准字段需显式映射(login、avatar_url)。

SAML 校验失败

  1. 证书必须是 PEM 内容且去掉头尾行。
  2. 确认 IdP 与服务器时间同步(偏差过大会被判定为无效响应)。
  3. 确认 idp_entity_id 与 IdP 元数据中的 Entity ID 完全一致。

飞书回调被拒或未创建账号

  1. 确认应用已登记该集成的回调地址(以飞书卡片显示的地址为准)。
  2. 确认登录 scope 包含 contact:user.email:readonly;通讯录中没有邮箱的账号还需 contact:user.employee_id:readonly,否则没有可据以推导占位邮箱的 user_id,首次登录会被拒绝。
  3. 飞书部门浏览或同步提示集成未启用时:先保存 App ID 和 App Secret,再启用飞书集成并打开通讯录同步开关。

关闭密码登录后无人能进后台

这是把站点切成 SSO-only 的典型事故:请先确认至少一个超级管理员已绑定身份连接。若已经锁死,需要平台运维在服务端恢复密码登录开关。

相关文档

这篇文章对你有帮助吗?

本页目录