当尝试验证用户的 jwt 不记名令牌时,我收到 403 错误,并且标头告诉我我的令牌范围不足。我想知道在对范围进行编码的过程中哪里出了问题,或者如果我解码令牌的方式不正确。
安全配置
@Configuration
public class SecurityConfiguration {
private final RSAKeyConfig keys;
public SecurityConfiguration(RSAKeyConfig keys) {
this.keys = keys;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationManager authManager(UserDetailsService detailsService) {
DaoAuthenticationProvider daoProvider = new DaoAuthenticationProvider();
daoProvider.setUserDetailsService(detailsService);
daoProvider.setPasswordEncoder(passwordEncoder());
return new ProviderManager(daoProvider);
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth -> auth
.requestMatchers("/auth/**").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/user/**").hasAnyRole("ADMIN", "USER")
.anyRequest().authenticated());
http
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(jwt -> jwt.jwtAuthenticationConverter(jwtConverter())));
http
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
return http.build();
}
@Bean
public JwtDecoder jwtDecoder() {
System.out.print("decoder");
return NimbusJwtDecoder.withPublicKey(keys.getPublicKey()).build();
}
@Bean
public JwtEncoder jwtEncoder() {
JWK jwk = new RSAKey.Builder(keys.getPublicKey())
.privateKey(keys.getPrivateKey()).build();
JWKSource<SecurityContext> jwks = new ImmutableJWKSet<>(new JWKSet(jwk));
return new NimbusJwtEncoder(jwks);
}
@Bean
public JwtAuthenticationConverter jwtConverter() {
System.out.println("jwt converter");
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName("roles");
jwtGrantedAuthoritiesConverter.setAuthorityPrefix("Roles_");
JwtAuthenticationConverter jwtconverter = new JwtAuthenticationConverter();
jwtconverter.setJwtGrantedAuthoritiesConverter(jwtGrantedAuthoritiesConverter);
return jwtconverter;
}
}
代币服务
@Service
public class TokenService {
@Autowired
private JwtEncoder jwtEncoder;
@Autowired
private JwtDecoder jwtDecoder;
public String generateJwt(Authentication auth) {
Instant now = Instant.now();
String scope = auth.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.joining(" "));
JwtClaimsSet claims = JwtClaimsSet.builder()
.issuer("self")
.issuedAt(now)
.subject(auth.getName())
.claim("roles", scope)
.build();
System.out.print(claims);
return jwtEncoder.encode(JwtEncoderParameters.from(claims))
.getTokenValue();
}
}
按键配置
@Component
@Data
public class RSAKeyConfig {
private RSAPublicKey publicKey;
private RSAPrivateKey privateKey;
public RSAKeyConfig(){
KeyPair pair = KeyGenerator.generateRsaKey();
this.publicKey = (RSAPublicKey) pair.getPublic();
this.privateKey = (RSAPrivateKey) pair.getPrivate();
}
}
密钥生成器
public class KeyGenerator {
public static KeyPair generateRsaKey(){
KeyPair keyPair;
try{
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
keyPair = keyPairGenerator.generateKeyPair();
}catch(Exception e){
throw new IllegalStateException();
}
return keyPair;
}
}
据我所知,您的 JWT 已定义范围,而不是角色 - 授权过程期望进行范围检查(作为权限),而不是角色检查?
.requestMatchers("/admin/**").hasRole("ADMIN")
尝试将此行更改为:
.requestMatchers("/admin/**").hasAuthority("SCOPE_ADMIN")