SSO
CETA上的应用除了支持用户名密码登录,还支持准的oauth2,cas,oidc协议的sso
1.文档
请先熟悉需要实现的SSO协议
2.原理
相信如果你已经通读了上述SSO协议,作为一个Client端,只需要关心怎么去调用认证服务(即redirect_uri),和认证完成的回调(即callback,通过callback确定是那个用户),刚好ceta提供了redirect_url和callback的扩展。
3.使用步骤
3.1 配置Login
配置登录方式,详情请看下图
- Unique Identifier : 唯一识别码
- Auth Type : 如果是用户名密码的用basic,sso的随意
- Login Property : 只有是basic的时候才需要配置,表示匹配用户表的那个字段,一般是email/nickname等
- Need Captcha : 是否需要验证码,也只有basic的时候才起作用
- Hide : 是否展示
- Default : 是否默认
- Order : 展示顺序
配置后的展示效果

3.2 配置 redirect_url 的flow
-
Rest trigger 要求:
- 必须是一个 REST-Flow。
- 使用 POST 请求。
- 需要一个输入参数:
loginMethod:当前登录方式,对应3.1 配置项。
-
流程输出设置:
- 输出值的键为
redirectUrl,内容为第三方认证服务的地址。
- 输出值的键为

3.3 配置callback 的flow
-
Rest trigger 要求:
- 必须是一个 REST-Flow。
- 使用 POST 请求。
- 需要两个输入参数:
loginMethod:当前登录方式,对应 3.1 配置项。callback:认证服务返回的内容。
-
流程输出设置:
- 必须包含以下四个值:
ssoUserId:SSO 用户的唯一标识。ssoType:选择登录方式的 3.1 配置项Auth Type。ssoEmail:用户邮箱。ssoPhone:用户电话号码。
- 必须包含以下四个值:
3.4 配置用户

- 登录类型: 支持那种sso,对应用户表的
sso_type - 统一登录用户名: SSO callback 的用户唯一标识,对应用户表的
sso_username - 允许本地登录: 是否允许用户名密码登录,对应用户表的
sso_allow_builtin
3.5 用户匹配
-
用户匹配逻辑
getSsoMappedUser:- 通过
ssoUserId、ssoType和projectToken查找用户。 - 首先尝试匹配
sso_type和sso_username。 - 如果找不到用户,检查
ssoUserId是否包含@:- 如果是邮箱地址,则匹配
sso_type和email。 - 否则,匹配
sso_type和username。
- 如果是邮箱地址,则匹配
- 过滤掉
sso_username为空的用户。 - 如果找到多个用户,抛出异常。
- 如果没有找到用户,返回
null。 - 返回找到的用户(如果有)。
- 通过
-
匹配步骤:
- 先用 3.3的
ssoUserId进行匹配。 - 如果找不到用户且 3.3的
ssoEmail不为空,再用 3.3的ssoEmail进行匹配。
- 先用 3.3的
代码中详细的描述了匹配规则
//用户匹配
private UserPo getSsoMappedUser(String ssoUserId, String ssoType, String projectToken) {
List<UserPo> users = userManagementRepository.findUserByProperties(
projectToken, Map.of(
"sso_type", ssoType,
"sso_username", ssoUserId
));
if (users.isEmpty()) {
if (ssoUserId.contains("@")) {
users = userManagementRepository.findUserByProperties(
projectToken, Map.of(
"sso_type", ssoType,
"email", ssoUserId
));
} else {
users = userManagementRepository.findUserByProperties(
projectToken, Map.of(
"sso_type", ssoType,
"username", ssoUserId
));
}
users = users.stream().filter(userPo -> StringUtils.isBlank(userPo.getSsoUsername())).collect(Collectors.toList());
}
if (users.size() > 1) {
throw new IllegalArgumentException("More than 1 user can login with ssoType: " + ssoType + " ssoId: " + ssoUserId);
}
if (users.isEmpty()) {
return null;
}
return users.get(0);
}
// loginMethodToken 是选择的认证类型
//先用**3.3**返回的ssoUserId匹配
UserPo user = getSsoMappedUser(ssoUserInfo.getSsoUserId(), loginMethodToken, projectToken);
if (null == user && ssoUserInfo.getSsoEmail() != null) {
//如果查找不到,再用**3.3**返回的ssoEmail匹配
user = getSsoMappedUser(ssoUserInfo.getSsoEmail(), loginMethodToken, projectToken);
}