java Spring Keycloak:获取用户 ID

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/45802797/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 08:54:48  来源:igfitidea点击:

Spring Keycloak: Get User ID

javaspringspring-bootkeycloak

提问by Daniel Pomrehn

I have developed a Spring Boot Webservice and use Keycloak for Access Management. The website stores some userdata in a database. I try to connect these data with the user logged in.

我开发了一个 Spring Boot Web 服务并使用 Keycloak 进行访问管理。该网站将一些用户数据存储在数据库中。我尝试将这些数据与登录的用户联系起来。

At the moment I store the username with the data. But I like to store the user id instead the username. How can I do that?

目前我将用户名与数据一起存储。但我喜欢存储用户 ID 而不是用户名。我怎样才能做到这一点?

I try to get SecurityContext by this:

我尝试通过以下方式获取 SecurityContext:

@Bean
@Scope(scopeName = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public KeycloakSecurityContext getKeycloakSecurityContext() {
    return ((KeycloakPrincipal<KeycloakSecurityContext>) getRequest().getUserPrincipal()).getKeycloakSecurityContext();
}

But I get an error:

但我收到一个错误:

There was an unexpected error (type=Internal Server Error, status=500).
Error creating bean with name 'scopedTarget.getKeycloakSecurityContext'
defined in com.SiteApplication: Bean instantiation via factory method
failed; nested exception is
org.springframework.beans.BeanInstantiationException: Failed to
instantiate [org.keycloak.KeycloakSecurityContext]: Factory method
'getKeycloakSecurityContext' threw exception; nested exception is
java.lang.ClassCastException:
org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken
cannot be cast to org.keycloak.KeycloakPrincipal

Is this the right way? What is missing?

这是正确的方法吗?缺什么?

Thank you!

谢谢!

回答by zakaria amine

I found a much simpler solution than the above:

我找到了一个比上面更简单的解决方案:

    @GetMapping
    public ResponseEntity getEndpoint(String someParam, HttpServletRequest request) {
        KeycloakAuthenticationToken principal = (KeycloakAuthenticationToken) request.getUserPrincipal();
        String userId = principal.getAccount().getKeycloakSecurityContext().getIdToken().getSubject();

        //....do something

        return new ResponseEntity(HttpStatus.OK);
    }

I think the exception you are getting above is because you are trying to cast getRequest().getUserPrincipal()to KeycloakPrincipal<KeycloakSecurityContext>while it is of type KeycloakAuthenticationToken, so ((KeycloakAuthenticationToken) getRequest().getUserPrincipal())would work.

我认为您遇到的例外情况是因为您试图在类型为 时强制getRequest().getUserPrincipal()转换KeycloakPrincipal<KeycloakSecurityContext>KeycloakAuthenticationToken,所以((KeycloakAuthenticationToken) getRequest().getUserPrincipal())会起作用。

回答by Jerry Saravia

I've done something similar in our code.

我在我们的代码中做了类似的事情。

public class AuthenticationTokenProcessingFilter extends GenericFilterBean {

        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

            if (!(request instanceof HttpServletRequest)) {
                throw new RuntimeException("Expecting a HTTP request");
            }

            RefreshableKeycloakSecurityContext context = (RefreshableKeycloakSecurityContext) request.getAttribute(KeycloakSecurityContext.class.getName());

            if (context == null) {
                handleNoSecurityContext(request, response, chain);
                return;
            }

            AccessToken accessToken = context.getToken();
            Integer userId = Integer.parseInt(accessToken.getOtherClaims().get("user_id").toString());

            chain.doFilter(request, response);
        }

}

Before you can do this you must add the user_idto the access tokens being issued by keycloak. You can do this through a mapper as shown in the screenshot below.

在您执行此操作之前,您必须将user_id加到由 keycloak 发布的访问令牌中。您可以通过映射器执行此操作,如下面的屏幕截图所示。

configuration for property mapper

属性映射器的配置

Also, don't forgot to add the processing filter from above to your application lifecycle by adding a @Beanmethod to your application class.

另外,不要忘记通过向@Bean应用程序类添加方法来将处理过滤器从上面添加到应用程序生命周期中。

@Configuration
@EnableAutoConfiguration(exclude = {FallbackWebSecurityAutoConfiguration.class, SpringBootWebSecurityConfiguration.class, DataSourceAutoConfiguration.class})
@ComponentScan
@EnableAsync
public class MyServiceClass {

    public static void main(String[] args) {
        Properties properties = new Properties();
        new SpringApplicationBuilder(MyServiceClass.class)
                .properties(properties)
                .bannerMode(Banner.Mode.OFF)
                .run(args);
    }


    @Bean
    public AuthenticationTokenProcessingFilter authFilter() {
        return new AuthenticationTokenProcessingFilter();
    }

}