Man*_*uel 7 authentication jwt keycloak
情况:我们使用keycloak通过使用JavaScript适配器的普通浏览器身份验证流程来验证Web应用程序(A)中的用户.这很完美!
目标:现在,新的用户组应该能够访问A.但是他们使用用户名和密码在受信任的第三方应用程序(B)中登录而没有Keycloak.在B中,它们具有到A的链接,其中包含自定义JWT(主要包含用户名和角色)作为查询参数.因此,当用户点击链接时,他会登陆我们的应用程序入口点,在那里我们可以从URL中读取JWT.现在需要做的是某种代币交换.我们希望将此自定义JWT发送给Keycloak,后者会将访问令牌发送回正常登录过程.
问题: Keycloak中是否有针对此类用例的内置支持?
尝试:
我尝试使用"签名JWT"创建一个机密客户端作为" 客户端身份验证器 ",如文档中所建议的那样.经过一些测试后,我认为这不是正确的轨道,即使名称很有希望.
另一个轨道是" 客户建议的身份提供商 ",通过实施自定义身份提供商.但是我没有看到,我如何在请求中发送JWT.
目前我正在尝试使用Autentication SPI通过自定义身份验证器扩展身份验证流程.
也许它比我想象的要简单得多.谁能引导我朝着正确的方向前进?
所以我终于能够用问题中提到的Authentication SPI解决它。
在 Keycloak 中,我复制了“浏览器”身份验证流程(因为您无法修改内置流程)并引入了一个额外的步骤“门户 JWT”(见下图)。然后我将它绑定到“绑定”选项卡中的“浏览器流”
“Portal JWT”后面是我的自定义身份验证器,它从重定向 uri 中的查询参数中提取 JWT 并对其进行解析以从中获取用户名和角色。然后将用户添加到具有自定义属性“isExternal”的 keycloak。这是它的摘录:
public class JwtAuthenticator implements Authenticator {
private final JwtReader reader;
JwtAuthenticator(JwtReader reader) {
this.reader = reader;
}
@Override
public void authenticate(AuthenticationFlowContext context) {
Optional<String> externalCredential = hasExternalCredential(context);
if (externalCredential.isPresent()) {
ExternalUser externalUser = reader.read(context.getAuthenticatorConfig(), externalCredential.get());
String username = externalUser.getUsername();
UserModel user = context.getSession().users().getUserByUsername(username, context.getRealm());
if (user == null) {
user = context.getSession().users().addUser(context.getRealm(), username);
user.setEnabled(true);
user.setSingleAttribute("isExternal", "true");
}
for (String roleName : externalUser.getRoles()) {
RoleModel role = context.getRealm().getRole(roleName);
if (role == null) {
role = context.getRealm().addRole(roleName);
}
user.grantRole(role);
}
context.setUser(user);
context.success();
} else {
context.attempted();
}
}
private Optional<String> hasExternalCredential(AuthenticationFlowContext context) {
String redirectUri = context.getUriInfo().getQueryParameters().getFirst("redirect_uri);
try {
List<NameValuePair> queryParams = URLEncodedUtils.parse(new URI(redirectUri), "UTF-8");
Optional<NameValuePair> jwtParam = queryParams.stream()
.filter(nv -> "jwt".equalsIgnoreCase(nv.getName())).findAny();
if (jwtParam.isPresent()) {
String jwt = jwtParam.get().getValue();
if (LOG.isDebugEnabled()) {
LOG.debug("JWT found: " + jwt);
}
return Optional.of(jwt);
}
} catch (URISyntaxException e) {
LOG.error("Redirect URL not as expected: " + redirectUri);
}
return Optional.empty();
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2689 次 |
| 最近记录: |