简体   繁体   English

Keycloak:使用自定义JWT对用户进行身份验证

[英]Keycloak: Authenticate user with a custom JWT

Situation: We use keycloak to authenticate users in our web application (A) through normal browser authentication flow using the JavaScript adapter. 情况:我们使用keycloak通过使用JavaScript适配器的普通浏览器身份验证流程来验证Web应用程序(A)中的用户。 This works perfectly! 这很完美!

Goal: Now, a new group of users should be able to access A. But they log in with username and password in a trusted third-party application (B) without Keycloak. 目标:现在,新的用户组应该能够访问A.但是他们使用用户名和密码在受信任的第三方应用程序(B)中登录而没有Keycloak。 In B they have a link to A with a custom JWT (essentially containing username and roles) as a query parameter. 在B中,它们具有指向A的链接,其中包含自定义JWT(主要包含用户名和角色)作为查询参数。 So when the user clicks on the link, he lands on our application entry point where we are able to read the JWT out of the URL. 因此,当用户点击链接时,他会登陆我们的应用程序入口点,在那里我们可以从URL中读取JWT。 What needs to happen now is some sort of token exchange. 现在需要做的是某种代币交换。 We want to send this custom JWT to Keycloak, which sends back an access token analog to the normal login process. 我们希望将此自定义JWT发送给Keycloak,后者会将访问令牌发送回正常登录过程。

Question: Is there built-in support in Keycloak for such a usecase? 问题: Keycloak中是否有针对此类用例的内置支持?

Attempts: 尝试:

I tried to create a confidential client with "Signed JWT" as " Client Authenticator " as suggested in the docs. 我尝试使用“签名JWT”创建一个机密客户端作为“ 客户端身份验证器 ”,如文档中所建议的那样。 After some testing I don't think this is the right track, even if the name is promising. 经过一些测试后,我认为这不是正确的轨道,即使名称很有希望。

Another track was " Client suggested identity provider " by implementing a custom identity provider. 另一个轨道是“ 客户建议的身份提供商 ”,通过实施自定义身份提供商。 But I don't see, how I can send the JWT within the request. 但是我没有看到,我如何在请求中发送JWT。

Currently I'm trying to use the Autentication SPI to extend the authentication flow with a custom authenticator. 目前我正在尝试使用Autentication SPI通过自定义身份验证器扩展身份验证流程。

Maybe it is much simpler than I think. 也许它比我想象的要简单得多。 Can anyone lead me in the right direction? 谁能引导我朝着正确的方向前进?

So I was finally able to solve it with the Authentication SPI mentioned in the question. 所以我终于能够使用问题中提到的Authentication SPI来解决它。

In Keycloak, I made a copy of the "browser" authentication flow (since you can not modify built-in flows) and introduced an additional step "Portal JWT" (see picture below). 在Keycloak中,我制作了一份“浏览器”认证流程(因为你无法修改内置流程)并引入了一个额外的步骤“Portal JWT”(见下图)。 I then bound it to "Browser Flow" in the "Bindings" tab 然后我将其绑定到“Bindings”选项卡中的“Browser Flow”

自定义验证流程

Behind "Portal JWT" is my custom authenticator which extracts the JWT from the query parameter in the redirect uri and parses it to get username and roles out of it. “Portal JWT”背后是我的自定义身份验证器,它从重定向uri中的查询参数中提取JWT并解析它以获取用户名和角色。 The user is then added to keycloak with a custom attribute "isExternal". 然后,用户将自定义属性“isExternal”添加到keycloak。 Here is an extract of it: 以下是它的摘录:

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();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 生成自定义jwt令牌并验证用户,Spring Security - Generate custom jwt-token and Authenticate user, Spring Security 使用Java中的Keycloak以编程方式验证用户身份 - Programmatically authenticate user with Keycloak in java 如何在 Keycloak 中使用手机号码验证用户身份 - How to authenticate user using mobile number in Keycloak 如何使用Firebase JWT在自定义后端上对用户进行身份验证? - How do I authenticate my user on a custom backend using my firebase JWT? 我可以在 keycloak 中添加自定义身份验证 rest api 吗? - Can I add custom authenticate rest api in keycloak? 如何检查来自另一个 keycloak 实例 B 的身份验证 keycloak 实例 A 用户? - How to check authenticate keycloak instance A user from another keycloak instance B? 如何使用Web API JWT令牌对MVC用户登录表单进行身份验证? - How to authenticate MVC user login form with web API JWT token? 无法对 Azure AD 中的自定义 API 进行身份验证(JWT 令牌问题) - Cannot authenticate to custom API in Azure AD (JWT token issue) 使用JWT - 是否可以通过主题作为电子邮件来验证用户? - Using JWT - is it fine to authenticate user with the subject being their email? 如何在 Jwt 模式下在 AdonisJs 中验证没有密码的用户? - How can authenticate an user without password in AdonisJs in Jwt mode?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM