Keycloak spring 适配器 - 检查每个 http 请求的 authToken 是否处于活动状态

Keycloak spring adapter - check that the authToken is active with every http request

我想解决的问题:

每次调用该服务时,我都想检查令牌是否处于活动状态,如果它不活动,我想将用户重定向到登录页面。

Current setup: Grails 3.2.9 , Keycloak 3.4.3

目前的想法:

这篇文章看起来很有前途:https://www.linkedin.com/pulse/json-web-token-jwt-spring-security-real-world-example-boris-trivic

在我的安全配置中,我添加了一个令牌过滤器

@Bean
public TokenAuthenticationFilter authenticationTokenFilter() throws Exception {
    return new TokenAuthenticationFilter();
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    super.configure http
    http
        .addFilterBefore(authenticationTokenFilter(), BasicAuthenticationFilter.class)
        .logout()
            .logoutSuccessUrl("/sso/login") // Override Keycloak's default '/'
        .and()
        .authorizeRequests()
            .antMatchers("/assets/*").permitAll()
            .anyRequest().hasAnyAuthority("ROLE_ADMIN") 
            .and()
        .csrf()
            .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());      
}

我的 TokenAuthenticationFilter 目前只打印出请求 headers :

public class TokenAuthenticationFilter extends OncePerRequestFilter { 

    private String getToken( HttpServletRequest request ) {

        Enumeration headerEnumeration = request.getHeaderNames();
        while (headerEnumeration.hasMoreElements()) {
            println "${ headerEnumeration.nextElement()}"
        }

        return null;
    }


    @Override
    public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {        
        String authToken = getToken( request );
    }

}

哪个returns:

我想在过滤器中实现的code/logic是这样的:

KeycloakAuthenticationToken token = SecurityContextHolder.context?.authentication 

RefreshableKeycloakSecurityContext context = token.getCredentials()

if(!context.isActive()){
    // send the user to the login page 
}

但是我不知道如何到达那里。 非常感谢任何帮助

据我了解,您的问题是关于 "how to check the token is active?" 而不是 "how to redirect the user to login page?"。

我看到你添加了标签 "spring-boot" 和 "keycloak" 也许你可以使用 "Keycloak Spring Boot Adapter"。假设你使用 Keycloak 的 3.4 版本(v4.0 仍处于测试版),你可以找到一些文档 here.

如果您不能(或不想)使用 Spring 启动适配器,这里是 KeycloakSecurityContextRequestFilter source code 的一部分,您的情况可能会很有趣:

KeycloakSecurityContext keycloakSecurityContext = getKeycloakPrincipal();
if (keycloakSecurityContext instanceof RefreshableKeycloakSecurityContext) {
    RefreshableKeycloakSecurityContext refreshableSecurityContext = (RefreshableKeycloakSecurityContext) keycloakSecurityContext;
    if (refreshableSecurityContext.isActive()) {
        ...
    } else {
        ...
    }
}

这里是 getKeycloakPrincipal 方法的 (Java) source code:

private KeycloakSecurityContext getKeycloakPrincipal() {
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

    if (authentication != null) {
        Object principal = authentication.getPrincipal();

        if (principal instanceof KeycloakPrincipal) {
            return KeycloakPrincipal.class.cast(principal).getKeycloakSecurityContext();
        }
    }

    return null;
}

如果您想了解如何在 SecurityContextHolder 中设置身份验证,请阅读来自 KeycloakAuthenticationProcessingFilterpiece of (Java) code

@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
    if (authResult instanceof KeycloakAuthenticationToken && ((KeycloakAuthenticationToken) authResult).isInteractive()) {
        super.successfulAuthentication(request, response, chain, authResult);
        return;
    }

    ...

    SecurityContextHolder.getContext().setAuthentication(authResult);

    ...

    try {
        chain.doFilter(request, response);
    } finally {
        SecurityContextHolder.clearContext();
    }
}

作为替代方案,您还可以检查这个 github dynamind 存储库: https://github.com/dynamind/grails3-spring-security-keycloak-minimal

希望能有所帮助。
最好的问候,
乔克.