Spring security OAuth2资源服务器JWT授权错误
Spring security OAuth2 Resource server JWT authorization error
配置
@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 引导版本 - 2.5.4
为什么 WebExpressionVoter 不解析授予的权限?我错过了什么?(也尝试使用实际的身份验证服务器,同样的错误)
我用 spring 引导的多个先前版本进行了测试,但没有任何乐趣。
任何advice/recommendations/suggestions请
在测试中您使用 ROLE_test_role
,在安全配置中您使用 test-role
- 一个带有连字符,一个带有下划线。我认为这就是问题所在。
配置
@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 引导版本 - 2.5.4 为什么 WebExpressionVoter 不解析授予的权限?我错过了什么?(也尝试使用实际的身份验证服务器,同样的错误) 我用 spring 引导的多个先前版本进行了测试,但没有任何乐趣。 任何advice/recommendations/suggestions请
在测试中您使用 ROLE_test_role
,在安全配置中您使用 test-role
- 一个带有连字符,一个带有下划线。我认为这就是问题所在。