java 如何根据来自payload claim JWT的角色访问REST端点

cbjzeqam  于 11个月前  发布在  Java
关注(0)|答案(2)|浏览(88)

我尝试根据声明中的角色对自己进行身份验证。基本上,我希望只有在声明中包含特定角色时才能连接到应用程序
学历:

<dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
          <version>3.1.4</version>
          <scope>compile</scope>
        </dependency>
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-security</artifactId>
          <version>3.1.4</version>
          <scope>compile</scope>
        </dependency>
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
          <version>3.1.4</version>
          <scope>compile</scope>
        </dependency>

字符集
这是我的安全课:

@Configuration
    @EnableWebSecurity(debug = true)
    @AllArgsConstructor
    public class SecurityOAuth2Config {
    
      private static final Logger LOGGER = LogManager.getLogger(SecurityOAuth2Config.class);
    
      @Bean
      public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    
        http
          .cors(AbstractHttpConfigurer::disable)
          .headers(header -> header.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))
          .csrf(AbstractHttpConfigurer::disable)
          .sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
          .authorizeHttpRequests(req -> req
            .requestMatchers(antMatcher("/actuator/health")).permitAll()
            .requestMatchers(antMatcher("/actuator/info")).permitAll()
            .requestMatchers(antMatcher("/h2-console/**")).permitAll()
            // Invoked internally inside the kubernetes cluster
            .requestMatchers(antMatcher("/internal/api/**")).permitAll()
            .requestMatchers(antMatcher("/api/**"))
            .hasAnyRole("User1", "Admin3","TestDataUploader")
            .anyRequest().permitAll()
          )
          .oauth2ResourceServer((oauth2) -> oauth2.jwt(jwtConfigurer ->
            jwtConfigurer.jwtAuthenticationConverter(jwtAuthenticationConverter())));
    
    
        return http.getOrBuild();
      }
    
      @Bean
      public JwtAuthenticationConverter jwtAuthenticationConverter() {
        var grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
        grantedAuthoritiesConverter.setAuthoritiesClaimName("role");
        grantedAuthoritiesConverter.setAuthorityPrefix("");
        var jwtAuthenticationConverter = new JwtAuthenticationConverter();
        jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter);
        return jwtAuthenticationConverter;
      }
    
      @Bean
      public GrantedAuthoritiesMapper userAuthoritiesMapper() {
        return (authorities) -> {
          Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
          LOGGER.info("AUTHORITIES " +  authorities);
          authorities.forEach(authority -> {
            if (authority instanceof OidcUserAuthority oidcAuth) {
              oidcAuth.getUserInfo().getClaimAsStringList("role").forEach(
                role -> mappedAuthorities.add(new SimpleGrantedAuthority("" + role)));
            }
          });
          mappedAuthorities.addAll(authorities);
    
          return mappedAuthorities;
        };
      }
    }


我一直都没得到授权
承载令牌示例

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1699881658,
  "iss": "https://id.test.io/",
  "upn": "Jon",
  "role": [
    "Admin",
    "Approve"
  ]
}


控制器端点示例

@RestController
    @RequestMapping("/api")
    @AllArgsConstructor
    public class ApplicationListController {
      private ServiceApp serviceApp;

     @GetMapping("/app")
     public Collection<Response> getApplications() {
       return serviceApp.loadResponse();
    }
   }

9q78igpj

9q78igpj1#

你应该删除你的GrantedAuthoritiesMapper bean,它复制了你已经在JwtAuthenticationConverter上配置的东西。
当使用.hasAnyRole("User1", "Admin3","TestDataUploader")时,您希望身份验证包含ROLE_User1ROLE_Admin3ROLE_TestDataUploader权限之一,但您Map的"role": [ "Admin", "Approve" ]声明没有前缀=>权限为AdminApprove =>由于缺少ROLE_前缀且预期角色为Admin3,因此不匹配(不是您索赔中所含的Admin)。三种选择:

  • 将访问控制规则更改为.hasAnyAuthority("User1", "Admin","TestDataUploader")
  • 将访问控制规则更改为.hasAnyRole("User1", "Admin","TestDataUploader")并将JwtAuthenticationConverter更新为grantedAuthoritiesConverter.setAuthorityPrefix("ROLE_");
  • 将授权服务器上的角色名称从Admin3更改为ROLE_Admin(令牌中的声明将为"role": [ "ROLE_Admin3", "ROLE_Approve" ]

尝试使用以下conf:

@Configuration
@EnableWebSecurity(debug = true)
@AllArgsConstructor
public class SecurityOAuth2Config {
    
      private static final Logger LOGGER = LogManager.getLogger(SecurityOAuth2Config.class);
    
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http, JwtAuthenticationConverter jwtAuthenticationConverter) throws Exception {
        http
          .cors(AbstractHttpConfigurer::disable)
          .headers(header -> header.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))
          .csrf(AbstractHttpConfigurer::disable)
          .sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
          .authorizeHttpRequests(req -> req
            .requestMatchers(antMatcher("/actuator/health")).permitAll()
            .requestMatchers(antMatcher("/actuator/info")).permitAll()
            .requestMatchers(antMatcher("/h2-console/**")).permitAll()
            // Invoked internally inside the kubernetes cluster
            .requestMatchers(antMatcher("/internal/api/**")).permitAll()
            .requestMatchers(antMatcher("/api/**"))
            .hasAnyRole("Admin", "User1", "TestDataUploader")
            .anyRequest().permitAll()
          )
          .oauth2ResourceServer((oauth2) -> oauth2.jwt(jwtConfigurer ->
            jwtConfigurer.jwtAuthenticationConverter(jwtAuthenticationConverter)));

        return http.getOrBuild();
    }
    
    @Bean
    public JwtAuthenticationConverter jwtAuthenticationConverter() {
        var grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
        grantedAuthoritiesConverter.setAuthoritiesClaimName("role");
        grantedAuthoritiesConverter.setAuthorityPrefix("ROLE_");
        var jwtAuthenticationConverter = new JwtAuthenticationConverter();
        jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter);
        return jwtAuthenticationConverter;
    }
}

字符集
作为替代方案,您可以使用我的启动器沿着方法安全性,这可能会使您的生活更轻松:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>

<dependency>
    <groupId>com.c4-soft.springaddons</groupId>
    <artifactId>spring-addons-starter-oidc</artifactId>
    <version>7.1.13</version>
</dependency>
# The following replaces spring.security.oauth2.resourceserver properties
com:
  c4-soft:
    springaddons:
      oidc:
        ops:
        # Change this to point to your own authorization server
        - iss: https://localhost:8443/realms/master
          username-claim: upn
          authorities:
          - path: $.roles
            prefix: ROLE_
        resourceserver:
          permit-all:
          - /actuator/health
          - /actuator/info
          - /h2-console/**
          - /internal/api/**
          cors:
@Configuration
@EnableWebSecurity(debug = true)
@EnableMethodSecurity
@AllArgsConstructor
public class SecurityOAuth2Config {
    // Yes, that simple, the stateless resource server filter-chain is created for you,
    // based on the application properties above
}
@RestController
@RequestMapping("/api")
@AllArgsConstructor
public class ApplicationListController {
    private ServiceApp serviceApp;

    @GetMapping("/app")
    @PreAuthorize("hasAnyRole('Admin', 'User1', 'TestDataUploader')")
    public Collection<Response> getApplications() {
        return serviceApp.loadResponse();
    }
}
gg58donl

gg58donl2#

给予访问权限,使用@PreAuthorize("hasAnyAuthority('role')")访问控制器

@RestController
@RequestMapping("/api")
@AllArgsConstructor
public class ApplicationListController {
    private ServiceApp serviceApp;

    @GetMapping("/app")
    @PreAuthorize("hasAnyAuthority('Admin','Approve')")
    public Collection<Response> getApplications() {
        return serviceApp.loadResponse();
    }
}

字符集

相关问题