我正在try 使用OAuth 2.0资源服务器JWT在一个简单的应用程序中使用JWT配置访问授权.
整个身份验证部分工作正常,但我在授权方面遇到了问题.即使令牌中存在正确的授权,所有受保护的端点也会给出403 Forbidden
错误.
我try 使用默认作用域(SCOPE_)属性,并将配置更改为ROLES(ROLE_),但问题仍然存在.
有谁知道怎么解这个题吗?
Complete source code:https://github.com/GustavoSC1/spring-security-jwt
Example of generated token: eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJzcHJpbmctc2VjdXJpdHktand0Iiwic3ViIjoidXNlcm5hbWUiLCJleHAiOjE3MDU0NDMyOTQsImlhdCI6MTcwNTQwNzI5NCwicm9sZXMiOiJST0xFX0FETUlOIn0.peivwrtHx_7mr6eefqbiD5DplhFFzcVd7sCMmt3f7rk7Sk1i6KeRPQi5ubdvaEfnZSJQ6VKA5NAdltSbqidfzogmoIXjktfhsc5ZrNYyRhikVnWcWb3wRGdd1EZgIHALDFjXWXsyypauNjWdxZNiRKL93e6MG1uAo5pIy9p-9YP8JEr7O31wKDR1COSKzK3gQw42uecIB9H1rRlkx9pdk7Pf9RtfsSfCwc-NtViSMryCrecO9RiaLqFYdpdzeojiMcbqVEyBoqFhN2WoEpgDM8mR5zSdhGdQE1IVsIbfbCJ_0486ZuQiKsXP2kniljHL2b5qnaN07FJPVslK--Ccsg
SecurityConfig:个
@Configuration
@EnableWebSecurity
//@EnableMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
@Value("${jwt.public.key}")
private RSAPublicKey key;
@Value("${jwt.private.key}")
private RSAPrivateKey priv;
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(
auth -> auth
.requestMatchers("/authenticate").permitAll()
.requestMatchers("/register").permitAll()
.requestMatchers("/private").hasAnyRole("ADMIN"))
.httpBasic(Customizer.withDefaults())
// https://docs-spring-io.translate.goog/spring-security/reference/servlet/oauth2/resource-server/jwt.html?_x_tr_sl=en&_x_tr_tl=pt&_x_tr_hl=pt-BR&_x_tr_pto=sc
.oauth2ResourceServer(
conf -> conf.jwt(
jwt -> jwt.decoder(jwtDecoder())
.jwtAuthenticationConverter(jwtAuthenticationConverter())));
return http.build();
}
@Bean
public JwtAuthenticationConverter jwtAuthenticationConverter() {
JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
grantedAuthoritiesConverter.setAuthoritiesClaimName("roles");
grantedAuthoritiesConverter.setAuthorityPrefix("ROLE_");
JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter);
return jwtAuthenticationConverter;
}
@Bean
JwtDecoder jwtDecoder() {
return NimbusJwtDecoder.withPublicKey(this.key).build();
}
@Bean
JwtEncoder jwtEncoder() {
JWK jwk = new RSAKey.Builder(this.key).privateKey(this.priv).build();
JWKSource<SecurityContext> jwks = new ImmutableJWKSet<>(new JWKSet(jwk));
return new NimbusJwtEncoder(jwks);
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
UserDetailsServiceImpl:个
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
private final UserRepository userRepository;
public UserDetailsServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Optional<User> userOptional = userRepository.findByUsername(username);
User user = userOptional.orElseThrow(() -> new UsernameNotFoundException("User Not Found with username: " + username));
return new UserAuthenticated(user.getUsername(), user.getPassword());
}
}
UserAuthenticated:个
public class UserAuthenticated implements UserDetails {
private String username;
private String password;
public UserAuthenticated(String username, String password) {
this.username = username;
this.password = password;
}
@Override
public String getUsername() {
return username;
}
@Override
public String getPassword() {
return password;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return List.of(() -> "ROLE_ADMIN");
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
JwtService:个
@Service
public class JwtService {
private final JwtEncoder encoder;
public JwtService(JwtEncoder encoder) {
this.encoder = encoder;
}
public String generateToken(Authentication authentication) {
Instant now = Instant.now();
long expiry = 36000L;
String scope = authentication
.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors
.joining(" "));
JwtClaimsSet claims = JwtClaimsSet.builder()
.issuer("spring-security-jwt")
.issuedAt(now)
.expiresAt(now.plusSeconds(expiry))
.subject(authentication.getName())
.claim("roles", scope)
.build();
return encoder.encode(
JwtEncoderParameters.from(claims))
.getTokenValue();
}
}
PrivateController:个
@RestController
@RequestMapping("private")
public class PrivateController {
@GetMapping
//@PreAuthorize("hasAuthority('ROLE_ADMIN')")
public String getMessage() {
return "Hello from private API controller";
}
}