java - Webflux 和 keycloak 在 jwt 中使用方法安全级别@Preauthorize 自定义声明而不是默认范围

标签 java spring-security keycloak spring-webflux spring-security-oauth2

根据标题,我正在像这样设置 webflux 配置

@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class WebSecurityConfig {
String jwkSetUri = "http://localhost:8080/auth/realms/demo/protocol/openid-connect/certs";
@Bean 
public ReactiveJwtDecoder jwtDecoder() {

return 
ReactiveJwtDecoders.fromIssuerLocation("http://localhost:8080/auth/realms/demo");
}
 @Bean

public SecurityWebFilterChain configure(ServerHttpSecurity http) {

     http.authorizeExchange()

           
            .oauth2Login()

            .and()
          .
            ...
             .oauth2ResourceServer()
             .jwt()

    .jwkSetUri(jwkSetUri)

            // .jwtDecoder(jwtDecoder())

             .jwtAuthenticationConverter(grantedAuthoritiesExtractor());
            return http.build();
}

@Bean

Converter<Jwt, Mono<AbstractAuthenticationToken>> grantedAuthoritiesExtractor() {

    GrantedAuthoritiesExtractor extractor = new GrantedAuthoritiesExtractor();

    return new ReactiveJwtAuthenticationConverterAdapter(extractor);

}
static class GrantedAuthoritiesExtractor

       extends  JwtAuthenticationConverter {


    public Collection<GrantedAuthority> extractAuthorities(Jwt jwt) {

        Collection<?> authorities = (Collection<?>)

                jwt.getClaims().getOrDefault("roles", Collections.emptyList());


        return authorities.stream()

                .map(Object::toString)

                .map(SimpleGrantedAuthority::new)

                .collect(Collectors.toList());
    }
}

使用以下 application.yml

security:
   oauth2:

     client:
       provider:
         keycloak-local:
           issuer-uri: http://localhost:8080/auth/realms/demo
       registration:
         keycloak-local:
           client-id: some-id
           client-secret: ...

     resourceserver:
       jwt:
     
         issuer-uri: http://localhost:8080/auth/realms/demo
         jwk-set-uri: http://localhost:8080/auth/realms/demo/protocol/openid- 
         connect/certs

 

token 格式是这样的

"realm_access": {
"roles": [
 "offline_access",
  "uma_authorization"
  ]
   },
 "resource_access": {
 "someclient": {
  "roles": [
    "uma_protection"
   ]
  },
  "account": {
    "roles": [
    "manage-account",
    "manage-account-links",
    "view-profile"
  ]
   }
   },
   "scope": "profile  email ",
   "organizationId": "605b74813bd72c65a24a1704",
   "accountId": "605b74813bd72c65a24a1709",
   "email_verified": false,
   "roles": [
   "ROLE_ADMIN"    
     ],
   "preferred_username": "someUsername",
   "userId": "605b74813bd72c65a24a1706",
   "email": "email.com"
    }`


    
  

当然,“角色”数组是我最想访问的数组(是我在我的数据库中定义的角色)。

设置之后似乎没有任何变化。 所以在我的 Controller 中我尝试使用 @Preauthorize 注释以访问某些方法,但它会继续使用范围声明。

@PreAuthorize("hasAuthority('SCOPE_email')")

有谁知道我错过了什么?请注意,我引用了官方文档,但也引用了 this tutorial . 对于 webflux。

谢谢

最佳答案

默认情况下,Spring Security 转换scopescp 声明中的项目并使用SCOPE_ 前缀。如果您的应用程序是纯 OAuth2 资源服务器,您可以通过定义自定义 ReactiveJwtAuthenticationConverter bean 来更改这两个约定。

例如,要从 roles 范围导出权限并使用 `` 前缀(因为 ROLE_ 已经是您的角色名称的一部分),您可以定义以下内容 bean 。 Spring Security 会自动获取它,您不需要从 SecurityWebFilterChain 配置中引用它。

@Bean
public ReactiveJwtAuthenticationConverter jwtAuthenticationConverter() {
    var jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
    jwtGrantedAuthoritiesConverter.setAuthorityPrefix("ROLE_");
    jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName("roles");

    var jwtAuthenticationConverter = new ReactiveJwtAuthenticationConverter();
    jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(
            new ReactiveJwtGrantedAuthoritiesConverterAdapter(jwtGrantedAuthoritiesConverter));

    return jwtAuthenticationConverter;
}

由于您的应用程序还配置为 OAuth2 客户端(使用 oauth2Login()),因此您需要一种不同的方法。您可以定义 GrantedAuthoritiesMapperOAuth2UserService。可以在 Spring Security documentation 中找到这两个选项的示例。 .

关于java - Webflux 和 keycloak 在 jwt 中使用方法安全级别@Preauthorize 自定义声明而不是默认范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67284770/

相关文章:

java - 使用 Java 将 JSON 元素附加到文件中的 JSON 数组

java - asdf install [警告] JVM 风格 'sun' 不理解

java - 在 Sikuli X Java 中查找图像

java - 无法在 (CLI) 中使用 Ant v1.9.4 编译 Java-8 源代码

java - Spring mongodb 异常 HTTP Status 500 - 过滤器执行抛出异常

grails - 将 Grails 与 Spring Social(Facebook、Twitter 和 Google)集成需要什么

Grails 预验证场景

java - 配置在测试中被忽略

ssl - 如何使用反向代理修复Keycloak中的 "We'抱歉需要HTTPS?

spring-boot - 如何将Keycloak注册到Spring Eureka Server