英文:
Recieve "Insufficient scope" error even though i have sufficient one
问题
Here's the translated content:
实现JWT令牌身份验证,使用OAuth2ResourceServer(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服务器工作的方式)。有人可以解释一下OAuth2ResourceServer如何检查范围的方式,以及我应该尝试修复问题的方法吗?
英文:
Implementing authentication via JWT token, using OAuth2ResourceServer (Spring 3)
spring security config:
@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;
}
}
So my tokens contains claim "scope" with value "SCOPE_usr" which required on "/credit/request" endpoint, even though server continues to response with 403 code error and "insufficient scope" message. I tried to hardcode scope to "SCOPE_usr" in JwtTokenService, so all my tokens pass the endpoint check (I understand, that it may sound stupid, but at this moment that's the way I think OAuth2 server works). Can somebody explain, which way OAuth2ResourceServer checks scopes, and what should I try to fix that problem?
答案1
得分: 1
你正在使用默认的权限转换器,该转换器接受范围声明条目并在其前加上“SCOPE_”前缀。使用此转换器和您在配置中拥有的requestMatchers
访问规则,令牌中的范围应为usr
(将被转换为SCOPE_usr
权限)。
英文:
You are using the default authorities converter which takes scope claim entries and adds SCOPE_
prefix to it. With this converter and the requestMatchers
access rules you have in your conf, the scope in the token should be usr
(which will be converted to SCOPE_usr
authority).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论