为啥我收到 Spring Security 和 Keycloak 的“访问被拒绝”错误?

Posted

技术标签:

【中文标题】为啥我收到 Spring Security 和 Keycloak 的“访问被拒绝”错误?【英文标题】:Why I get a "Access is denied" error by Spring Security and Keycloak?为什么我收到 Spring Security 和 Keycloak 的“访问被拒绝”错误? 【发布时间】:2020-04-26 01:16:52 【问题描述】:

我用 Docker 设置了一个 Keycloak 服务器。配置领域和客户端等。我成功地为一些 RestControllers 编写了 Spring Boot 服务。工作等等。

但是当我尝试将 Spring Security 与 Keycloak Adapter 一起使用时,我被卡住了。

这是我的安全配置:

@KeycloakConfiguration
class SecurityConfig : KeycloakWebSecurityConfigurerAdapter() 

    @Autowired
    lateinit var keycloakClientRequestFactory: KeycloakClientRequestFactory

    @Bean
    fun keycloakConfigResolver(): KeycloakSpringBootConfigResolver = KeycloakSpringBootConfigResolver()

    @Bean
    override fun sessionAuthenticationStrategy(): SessionAuthenticationStrategy =
        NullAuthenticatedSessionStrategy()

    @Autowired
    @Throws(Exception::class)
    fun configureGlobal(auth: AuthenticationManagerBuilder) 
        val keycloakAuthProvider: KeycloakAuthenticationProvider = keycloakAuthenticationProvider()
        keycloakAuthProvider.setGrantedAuthoritiesMapper(SimpleAuthorityMapper())
        auth.authenticationProvider(keycloakAuthProvider)
    

    @Throws(Exception::class)
    override fun configure(http: HttpSecurity) 
        super.configure(http)
        http.cors().disable()
            .csrf().disable()
            .exceptionHandling().and()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .sessionAuthenticationStrategy(sessionAuthenticationStrategy()).and()
            .formLogin().disable()
            .authorizeRequests()
            .antMatchers("/apps/manual-data-collection/**").hasRole("user")
            .anyRequest().permitAll()
    

    /**
     * https://www.keycloak.org/docs/latest/securing_apps/index.html#avoid-double-bean-registration
     */
    @Bean
    @ConditionalOnMissingBean(HttpSessionManager::class)
    override fun httpSessionManager(): HttpSessionManager = HttpSessionManager()



现在我尝试访问服务器,但收到 403 禁止错误。以下是spring的日志:

2020-01-08 14:08:01.817 DEBUG 12396 --- [nio-8080-exec-5] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/apps/manual-data-collection/document-templates'; against '/apps/manual-data-collection/**'
2020-01-08 14:08:01.817 DEBUG 12396 --- [nio-8080-exec-5] o.s.s.w.a.i.FilterSecurityInterceptor    : Secure object: FilterInvocation: URL: /apps/manual-data-collection/document-templates; Attributes: [hasRole('ROLE_user')]
2020-01-08 14:08:01.817 DEBUG 12396 --- [nio-8080-exec-5] o.s.s.w.a.i.FilterSecurityInterceptor    : Previously Authenticated: org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken@bc432bbc: Principal: willy; Credentials: [PROTECTED]; Authenticated: true; Details: org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount@42db7613; Not granted any authorities
2020-01-08 14:08:01.818 DEBUG 12396 --- [nio-8080-exec-5] o.s.s.access.vote.AffirmativeBased       : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@3d0602a7, returned: -1
2020-01-08 14:08:01.818 DEBUG 12396 --- [nio-8080-exec-5] o.s.s.w.a.ExceptionTranslationFilter     : Access is denied (user is not anonymous); delegating to AccessDeniedHandler

org.springframework.security.access.AccessDeniedException: Access is denied

让我感到困惑的是,它说:Not granted any authorities。如果我省略部分,一切正常。必要的角色(在本例中为“用户”)存储在领域中。 JWT 令牌也提供这些。我不知道为什么它不起作用。

编辑: 我应该提一下。 Spring Boot Server 只能用作 Angular 应用程序的 REST 服务器,因此是STATELESS

【问题讨论】:

只是猜测:hasRole('ROLE_user') 可能表明 Spring 安全性正在寻找一个名为 ROLE_user 的角色。你在你的领域是这样命名的吗? 在领域中的角色是user。 Spring Security 使用了前缀ROLE_,所以我使用了SimpleAuthorityMapper 将keycloak 角色映射到spring 角色。还是我误会了什么?不过,我只是创建了一个名为ROLE_user 的角色。不幸的是,它也不起作用。 .antMatchers("/apps/manual-data-collection/**").hasRole("user")更改为.antMatchers("/apps/manual-data-collection/**").hasRole("ROLE_user") @BilalShah 然后我得到一个错误:IllegalArgumentException: role should not start with 'ROLE_' since it is automatically inserted. Got 'ROLE_user' @BilalShah 因为他使用 Keycloak,所以没有(直接)数据库身份验证。另请注意,用户确实存在 (Authenticated: true),但角色似乎不匹配。 【参考方案1】:

好的,我发现了我的错误。我在 application.yml 中激活了以下内容:

keycloak.use-resource-role-mappings=true

但必须是false。 Keycloak documentation 如下:

使用资源角色映射 - 如果设置为 true,适配器将在令牌内部查找用户的应用程序级角色映射。如果为 false,它将查看域级别的用户角色映射。这是可选的。默认值为 false。

【讨论】:

谢谢!这拯救了我的一天! 完美,绝对有效!

以上是关于为啥我收到 Spring Security 和 Keycloak 的“访问被拒绝”错误?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Spring Security 身份验证会导致 CORS 错误

为啥我无法使用 grails 框架 1.3.7 中安装的 spring security 和 weceem 插件登录

为啥在 Spring Saml 中忽略 cacerts?

为啥这个基于令牌的 Spring Security 过滤器没有被调用?

spring-security 收到空凭据(用户名和密码)时如何创建自定义响应?

为啥spring-security-oauth oauth 2.0实现中需要scope参数