Keycloak弹簧适配器 - 检查authToken是否对每个http请求都有效

时间:2018-04-26 10:31:54

标签: spring-boot keycloak grails3

我想解决的问题: 对于每次对服务的调用,我想检查令牌是否处于活动状态 - 如果它处于非活动状态,我想将用户重定向到登录页面。

当前设置: 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());      
}

My TokenAuthenticationFilter目前只打印出请求标题:

公共类TokenAuthenticationFilter扩展了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 );
}

}

返回:

  • 主持人
  • user-agent
  • 接受
  • 接受语言
  • 接受编码
  • 饼干
  • 连接
  • 升级不安全-请求
  • 缓存控制

我想在过滤器中实现的代码/逻辑类似于:

    KeycloakAuthenticationToken token = SecurityContextHolder.context?.authentication 

    RefreshableKeycloakSecurityContext context = token.getCredentials()

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

然而,我失去了如何到达那里。 任何帮助非常感谢

1 个答案:

答案 0 :(得分:3)

据我了解,您的问题是“如何检查令牌是否有效?”而不是“如何将用户重定向到登录页面?”。

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

如果您不能(或不想)使用Spring Boot Adapter,那么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中设置身份验证,请阅读KeycloakAuthenticationProcessingFilter中的piece 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存储库: https://github.com/dynamind/grails3-spring-security-keycloak-minimal

希望能有所帮助 最好的问候,
Jocker。