使用OAuth2 ResourceServer通过JWT令牌实现身份验证(Spring 3)
spring安全配置:
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
@Configuration
@RequiredArgsConstructor
public class SpringSecurityConfig {
private final AuthenticationService authenticationService;
private final PasswordEncoder passwordEncoder;
private final RsaProperties rsaKeys;
@Bean
public AuthenticationManager authManager() {
var authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(authenticationService);
authProvider.setPasswordEncoder(passwordEncoder);
return new ProviderManager(authProvider);
}
@Bean
public JwtEncoder jwtEncoder() {
JWK jwk = new RSAKey.Builder(rsaKeys.publicKey()).privateKey(rsaKeys.privateKey()).build();
JWKSource<SecurityContext> jwkSource = new ImmutableJWKSet<>(new JWKSet(jwk));
return new NimbusJwtEncoder(jwkSource);
}
@Bean
public JwtDecoder jwtDecoder() {
return NimbusJwtDecoder.withPublicKey(rsaKeys.publicKey()).build();
}
@Bean
public JwtTokenService tokenService() {
return new JwtTokenService(jwtEncoder());
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
return httpSecurity
.csrf().disable()
.authorizeHttpRequests()
.requestMatchers("/authentication/login").permitAll()
.requestMatchers("/credit/request").hasAuthority("SCOPE_usr")
.and()
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.oauth2ResourceServer(OAuth2ResourceServerConfigurer :: jwt )
.build();
}
}
JwtTokenService:
@Component
@RequiredArgsConstructor
public class JwtTokenService {
private final JwtEncoder jwtEncoder;
public String generateAccessToken(UserDetailsEntity userDetails) {
Instant now = Instant.now();
String scope = userDetails.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.joining(" "));
JwtClaimsSet claims = JwtClaimsSet.builder()
.issuer("self")
.issuedAt(now)
.expiresAt(now.plus(2, ChronoUnit.HOURS))
.subject(userDetails.getUsername())
.claim("scope", scope)
.build();
return this.jwtEncoder.encode(JwtEncoderParameters.from(claims)).getTokenValue();
}
public String generateRefreshToken(UserDetailsEntity userDetails) {
Instant now = Instant.now();
String scope = userDetails.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.joining(" "));
JwtClaimsSet claims = JwtClaimsSet.builder()
.issuer("self")
.issuedAt(now)
.expiresAt(now.plus(10, ChronoUnit.HOURS))
.subject(userDetails.getUsername())
.claim("scope", scope)
.build();
return this.jwtEncoder.encode(JwtEncoderParameters.from(claims)).getTokenValue();
}
public String parseToken(String token) {
try {
SignedJWT decodedJwt = SignedJWT.parse(token);
return decodedJwt.getJWTClaimsSet().getSubject();
} catch (ParseException e) {
System.out.println(e.getStackTrace());
}
return null;
}
}
因此,我的令牌包含声明“scope”,值为“SCOPE_usr”,这是“/credit/request”端点所需的,即使服务器继续响应403代码错误和“范围不足”消息。我尝试在JwtTokenService中将作用域硬编码为“SCOPE_usr”,这样我所有的令牌都通过了端点检查(我明白,这听起来可能很愚蠢,但目前我认为OAuth2服务器就是这样工作的)。有人能解释一下,OAuth2 ResourceServer检查作用域的方式是什么,我应该怎么解决这个问题?
1条答案
按热度按时间kr98yfug1#
您使用的是默认的权限转换器,它接受范围声明条目并为其添加
SCOPE_
前缀。使用此转换器和您在conf中的requestMatchers
访问规则,令牌中的范围应该是usr
(将转换为SCOPE_usr
权限)。