Keycloak 说 403 Forbidden for HTTP 方法而不是 GET

Posted

技术标签:

【中文标题】Keycloak 说 403 Forbidden for HTTP 方法而不是 GET【英文标题】:Keycloak says 403 Forbidden for HTTP Methods other than GET 【发布时间】:2019-08-22 14:22:51 【问题描述】:

我正在设置一个 Keycloak 实例以与包含 Spring Security 的 Spring Boot 应用程序一起使用。我使用邮递员来测试服务。我从获取新的访问令牌开始,效果很好。当我对安全端点进行 HTTP GET 调用时 - 一切正常,人员返回。但是当我对安全端点进行 HTTP POST/PUT/DELETE 调用时,Keycloak 显示错误 403 Forbidden。请看一下并告诉我出了什么问题。

我已经测试了 http.csrf().disable() 选项,然后工作正常,但这不是生产的解决方案。

SecurityConfig.java

@Configuration
@EnableWebSecurity
@ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter 


    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) 
        KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
        keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
        auth.authenticationProvider(keycloakAuthenticationProvider);
    

    @Bean
    public KeycloakSpringBootConfigResolver KeycloakConfigResolver() 
        return new KeycloakSpringBootConfigResolver();
    

    @Bean
    @Override
    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() 
        return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
    

    @Override
    protected void configure(HttpSecurity http) throws Exception 
        super.configure(http);
        http
                .authorizeRequests()
                .antMatchers( "/api/**").hasRole("my_admin")
                .anyRequest().permitAll();
    

application.yml:

keycloak:
  auth-server-url: http://localhost:11080/auth
  realm: myrealm
  resource: myclient
  public-client: true
  principal-attribute: preferred_username
  ssl-required: external
  use-resource-role-mappings: true

来自应用程序的一些日志(keycloak 跟踪日志级别):

2019-04-01 14:04:54.741 DEBUG 2952 --- [io-1080-exec-10] o.k.adapters.PreAuthActionsHandler       : adminRequest http://localhost:1080/api/my-endpoint
2019-04-01 14:04:54.741 DEBUG 2952 --- [io-1080-exec-10] .k.a.t.AbstractAuthenticatedActionsValve : AuthenticatedActionsValve.invoke /api/my-endpoint
2019-04-01 14:04:54.741 DEBUG 2952 --- [io-1080-exec-10] o.k.a.AuthenticatedActionsHandler        : AuthenticatedActionsValve.invoke http://localhost:1080/api/my-endpoint
2019-04-01 14:04:54.741 DEBUG 2952 --- [io-1080-exec-10] o.k.a.AuthenticatedActionsHandler        : Policy enforcement is disabled.
2019-04-01 14:04:54.742 DEBUG 2952 --- [io-1080-exec-10] o.k.adapters.PreAuthActionsHandler       : adminRequest http://localhost:1080/error
2019-04-01 14:04:54.743 DEBUG 2952 --- [io-1080-exec-10] f.KeycloakAuthenticationProcessingFilter : Request is to process authentication
2019-04-01 14:04:54.743 DEBUG 2952 --- [io-1080-exec-10] f.KeycloakAuthenticationProcessingFilter : Attempting Keycloak authentication
2019-04-01 14:04:54.743 TRACE 2952 --- [io-1080-exec-10] o.k.adapters.RequestAuthenticator        : --> authenticate()
2019-04-01 14:04:54.743 TRACE 2952 --- [io-1080-exec-10] o.k.adapters.RequestAuthenticator        : try bearer
2019-04-01 14:04:54.743 DEBUG 2952 --- [io-1080-exec-10] o.k.a.BearerTokenRequestAuthenticator    : Found [1] values in authorization header, selecting the first value for Bearer.
2019-04-01 14:04:54.743 DEBUG 2952 --- [io-1080-exec-10] o.k.a.BearerTokenRequestAuthenticator    : Verifying access_token
2019-04-01 14:04:54.743 TRACE 2952 --- [io-1080-exec-10] o.k.a.BearerTokenRequestAuthenticator    :     access_token: eyJhbs...blablab....signature
2019-04-01 14:04:54.744 DEBUG 2952 --- [io-1080-exec-10] o.k.a.BearerTokenRequestAuthenticator    : successful authorized
2019-04-01 14:04:54.744 TRACE 2952 --- [io-1080-exec-10] o.k.a.RefreshableKeycloakSecurityContext : checking whether to refresh.
2019-04-01 14:04:54.744 TRACE 2952 --- [io-1080-exec-10] org.keycloak.adapters.AdapterUtils       : useResourceRoleMappings
2019-04-01 14:04:54.744 TRACE 2952 --- [io-1080-exec-10] org.keycloak.adapters.AdapterUtils       : Setting roles: 
2019-04-01 14:04:54.744 TRACE 2952 --- [io-1080-exec-10] org.keycloak.adapters.AdapterUtils       :    role: my_admin
2019-04-01 14:04:54.744 DEBUG 2952 --- [io-1080-exec-10] a.s.a.SpringSecurityRequestAuthenticator : Completing bearer authentication. Bearer roles: [my_admin] 
2019-04-01 14:04:54.745 DEBUG 2952 --- [io-1080-exec-10] o.k.adapters.RequestAuthenticator        : User 'my_user' invoking 'http://localhost:1080/error' on client 'myclient'
2019-04-01 14:04:54.745 DEBUG 2952 --- [io-1080-exec-10] o.k.adapters.RequestAuthenticator        : Bearer AUTHENTICATED
2019-04-01 14:04:54.745 DEBUG 2952 --- [io-1080-exec-10] f.KeycloakAuthenticationProcessingFilter : Auth outcome: AUTHENTICATED
2019-04-01 14:04:54.745 DEBUG 2952 --- [io-1080-exec-10] f.KeycloakAuthenticationProcessingFilter : Authentication success using bearer token/basic authentication. Updating SecurityContextHolder to contain: org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken@fb0506b7: Principal: my_user; Credentials: [PROTECTED]; Authenticated: true; Details: org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount@ecf147d; Granted Authorities: ROLE_my_admin
2019-04-01 14:04:54.745 DEBUG 2952 --- [io-1080-exec-10] o.k.a.AuthenticatedActionsHandler        : AuthenticatedActionsValve.invoke http://localhost:1080/error
2019-04-01 14:04:54.745 DEBUG 2952 --- [io-1080-exec-10] o.k.a.AuthenticatedActionsHandler        : Policy enforcement is disabled.

【问题讨论】:

如果您设置了 CSRF 保护,您还需要您的客户端发送 CSRF 令牌。如果你不是从邮递员那里做的,它会失败。 【参考方案1】:

你应该做以下两个配置:

    在 spring 配置中禁用 csrf http.csrf().disable() client 而不是 realm 中定义角色,并为用户分配客户端级别的角色

【讨论】:

我只需要禁用 CSRF 就可以解决这个问题,但是禁用 CSRF 可以吗?【参考方案2】:

我发现我没有在 ajax 请求中使用 CSRF 令牌。 Spring Security 自动启用 CSRF 保护。 CSRF 令牌是为首次调用 Web 服务自动生成的,它具有会话范围。您需要将该令牌保存在元标记中。每个非 GET 请求都需要包含 CSRF 令牌(GET 请求不需要使用 CSRF 令牌保护,因为它们旨在用于非修改 API 调用)。

解决方案:只需在 html 页面 (thymeleaf) 的标题中包含该行:<html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security"> <meta id="_csrf" name="_csrf" th:content="$_csrf.token"/>

并在标头中的 ajax 调用中使用它:headers: 'X-CSRF-TOKEN': $('#_csrf').attr('content') ,

【讨论】:

【参考方案3】:

是 Spring Security 提供的 CSRF 保护。您真的需要使用 Keycloak 令牌进行这种保护吗?令牌仅包含在 cookie 中还是也存在于 Authorization 标头中?

【讨论】:

身份令牌存储在cookies中,访问令牌在header中传递 如果访问令牌在标头中传递,则不需要 CSRF 令牌。看来您正在使用带有 spring security 和 keycloak 适配器的 Spring boot:不要忘记禁用 keycloak 适配器提供的 4 个过滤器,因为它们是由 Spring boot 自动注册的。

以上是关于Keycloak 说 403 Forbidden for HTTP 方法而不是 GET的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot - KeyCloak 指向 403 禁止

KeyCloak用户rest api返回403禁止,为啥?

Keycloak REST API 403 被禁止

403 spring-boot-2-keycloak-适配器

403 Forbidden是啥意思,谢谢

boto elastic beanstalk CreateApplicationVersion 403 Forbidden