Spring 3 OAuth2ResourceServer JWT认证出现"Insufficient scope"错误的问题排查求助
Spring 3 OAuth2ResourceServer JWT认证出现"Insufficient scope"错误的问题排查求助
各位大佬好,我最近在基于Spring 3搭建JWT认证服务,用OAuth2ResourceServer做资源服务器校验,但遇到了个头疼的问题:
我配置了/credit/request端点需要SCOPE_usr权限才能访问,生成的JWT Token里也确实包含scope claim且值为SCOPE_usr,但请求这个端点时始终返回403错误,提示"insufficient scope"。更奇怪的是,如果我在JwtTokenService里把scope硬编码成"SCOPE_usr",所有Token居然就能通过校验。
我现在有点摸不清头绪,想请教大家:OAuth2ResourceServer到底是怎么校验scope的?我该从哪些方向入手排查和修复这个问题?
先贴一下我的核心代码:
Spring Security配置类
@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(); } }
JWT Token生成服务类
@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; } }
我自己的猜测和尝试:
我怀疑是不是Spring解析scope的方式和我理解的不一样?比如它会给scope的值自动加前缀?但硬编码成SCOPE_usr又能通过,这让我完全搞不懂逻辑了。希望有经验的朋友能给我指条明路,谢谢大家!
备注:内容来源于stack exchange,提问作者iia.m.y
相关产品推荐
相关产品推荐

