Spring security OAuth2 资源服务器 JWT 授权错误

Posted

技术标签:

【中文标题】Spring security OAuth2 资源服务器 JWT 授权错误【英文标题】:Spring security OAuth2 Resource server JWT authorization error 【发布时间】:2021-10-29 21:09:54 【问题描述】:

配置

@EnableWebSecurity
class SecurityConfig extends WebSecurityConfigurerAdapter 

    @Value("$spring.security.oauth2.resourceserver.jwt.jwk-set-uri")
    String jwkSetUri;

    @Override
    protected void configure(HttpSecurity http) throws Exception 

        http.authorizeRequests(requests -> requests
                                .antMatchers(HttpMethod.GET, "/message/**").hasRole("test-role")
                                .anyRequest().authenticated()
                ).oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
    

    @Bean
    JwtAuthenticationConverter jwtAuthenticationConverter() 
        JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
        jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(new RoleMapper());
        return jwtAuthenticationConverter;
    

    @Bean
    JwtDecoder jwtDecoder() 
        return NimbusJwtDecoder.withJwkSetUri(jwkSetUri).build();
    

    @SuppressWarnings("unchecked")
    static class RoleMapper implements Converter<Jwt, Collection<GrantedAuthority>> 

        @Override
        public Collection<GrantedAuthority> convert(Jwt jwt) 
            final Map<String, Collection<String>> realmAccess = (Map<String, Collection<String>>) jwt.getClaims().get("realm_access");
            return realmAccess.get("roles").stream()
                    .map(roleName -> "ROLE_" + roleName)
                    .map(SimpleGrantedAuthority::new)
                    .collect(Collectors.toList());
        
    

测试

@Test
    void test() throws Exception 
        MockHttpServletResponse response = mvc.perform(get("/message")
                        .with(jwt().authorities(new SimpleGrantedAuthority("ROLE_test_role"))))
                .andReturn()
                .getResponse();
        assertThat(response.getStatus()).as("Response has incorrect HTTP status.").isEqualTo(HttpStatus.OK.value());
    

日志

2021-08-31 09:28:12.862 TRACE 119643 --- [           main] o.s.s.w.a.i.FilterSecurityInterceptor    : Authorizing filter invocation [GET /message] with attributes [hasRole('ROLE_test-role')]
2021-08-31 09:28:12.866 TRACE 119643 --- [           main] o.s.s.w.a.expression.WebExpressionVoter  : Voted to deny authorization
2021-08-31 09:28:12.866 TRACE 119643 --- [           main] o.s.s.w.a.i.FilterSecurityInterceptor    : Failed to authorize filter invocation [GET /message] with attributes [hasRole('ROLE_test-role')] using AffirmativeBased [DecisionVoters=[org.springframework.security.web.access.expression.WebExpressionVoter@2503ec73], AllowIfAllAbstainDecisions=false]
2021-08-31 09:28:12.867 TRACE 119643 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'delegatingApplicationListener'
2021-08-31 09:28:12.868 TRACE 119643 --- [           main] o.s.s.w.a.ExceptionTranslationFilter     : Sending JwtAuthenticationToken [Principal=org.springframework.security.oauth2.jwt.Jwt@bbd01fb9, Credentials=[PROTECTED], Authenticated=true, Details=null, Granted Authorities=[ROLE_test_role]] to access denied handler since access is denied

org.springframework.security.access.AccessDeniedException: Access is denied
    at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:73) ~[spring-security-core-5.5.2.jar:5.5.2]
    at org.springframework.security.access.intercept.AbstractSecurityInterceptor.attemptAuthorization(AbstractSecurityInterceptor.java:238) ~[spring-security-core-5.5.2.jar:5.5.2]

Spring Boot 版本 - 2.5.4 为什么 WebExpressionVoter 不解析授予的权限?我错过了什么?(也尝试了实际的身份验证服务器,同样的错误) 我用多个以前版本的 spring boot 进行了测试,但没有任何乐趣。 任何建议/建议/建议请

【问题讨论】:

我在这里创建了一个最小的、可重复的样本github.com/mparthasarathi429/security-demo 您在权限中添加了一个前缀,该前缀已经是ROLE_test_role,例如:.map(roleName -&gt; "ROLE_" + roleName)。你能试着去掉RoleMapper上的“ROLE_”前缀吗? @MarcusHertdaCoregio 尝试了您的建议。同样的错误 请将logging.level.org.springframework.security=TRACE 添加到您的属性文件中。您使用的是哪个 Spring Boot 和 Spring Security 版本? Spring Boot 版本 - 2.5.4 和 Spring Security - 5.5.2 【参考方案1】:

在测试中使用ROLE_test_role,在安全配置中使用test-role - 一个带有连字符,一个带有下划线。我认为这就是问题所在。

【讨论】:

叹息!重点关注角色前缀和遗漏的角色名称

以上是关于Spring security OAuth2 资源服务器 JWT 授权错误的主要内容,如果未能解决你的问题,请参考以下文章

Oauth2 资源服务器重叠 Spring Security 配置

Spring security OAuth2 资源服务器 JWT 授权错误

Spring Security 入门(1-3)Spring Security oauth2.0 指南

如何在 Spring Security 中动态指定 OAuth2 资源详细信息?

Spring security - oauth2 资源服务器测试

使用Spring Security登录认证,通过Oauth2.0开发第三方授授权访问资源项目详解