如何根据来自有效负载声明 JWT 的角色访问 REST 端点

问题描述 投票:0回答:1

我正在尝试根据我在声明中获得的角色来验证自己的身份。基本上,只有当特定角色是声明的一部分时,我才希望能够连接到我的应用程序

依赖关系:

    <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();
    }
   }
java spring jwt spring-security-oauth2
1个回答
0
投票

您应该删除您的

GrantedAuthoritiesMapper
bean,它会重复您在
JwtAuthenticationConverter
上配置的内容。

使用

.hasAnyRole("User1", "Admin3","TestDataUploader")
时,您希望身份验证包含
ROLE_User1
ROLE_Admin3
ROLE_TestDataUploader
权限之一,但映射不带前缀的
"role": [ "Admin", "Approve" ]
声明 => 权限是
Admin
Approve
=> 不匹配,因为缺少
ROLE_
前缀并且预期角色是
Admin3
(不是您声明中包含的
Admin
。两种选择

  • 将访问控制规则更改为
    .hasAnyAuthority("User1", "Admin","TestDataUploader")
  • 将访问控制规则更改为
    .hasAnyRole("User1", "Admin","TestDataUploader")
    并将您的
    JwtAuthenticationConverter
    更新为
    grantedAuthoritiesConverter.setAuthorityPrefix("ROLE_");

尝试使用以下配置:

@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>
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 {
}
@RestController
@RequestMapping("/api")
@AllArgsConstructor
public class ApplicationListController {
    private ServiceApp serviceApp;

    @GetMapping("/app")
    @PreAuthorize("hasAnyRole('Admin', 'User1', 'TestDataUploader')")
    public Collection<Response> getApplications() {
        return serviceApp.loadResponse();
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.