Spring Security OAuth2 JWT权限异常:已认证用户仍遭403拒绝
问题分析与解决方案
从你提供的堆栈日志能直接定位核心问题:认证后的用户实际持有的权限是SCOPE_USER,但你的配置要求的是USER权限,两者不匹配导致403拒绝访问。
日志里的关键信息:
Granted Authorities=[SCOPE_USER]
这说明Spring Security从JWT令牌中解析出的权限是SCOPE_USER,而你在Web Security配置中要求的是.hasAuthority("USER"),自然无法通过权限校验。
解决步骤
1. 确保JWT生成时正确写入用户权限
你的登录接口生成JWT时,需要把数据库中用户的权限(比如USER或ROLE_USER)写入JWT的Claims字段中。示例代码如下:
@PostMapping("/loginrest") public ResponseEntity<?> login(@RequestBody LoginRequest request) { // 用户认证逻辑 Authentication authentication = authenticationManager.authenticate( new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword()) ); SecurityContextHolder.getContext().setAuthentication(authentication); // 提取用户权限 List<String> authorities = authentication.getAuthorities().stream() .map(GrantedAuthority::getAuthority) .collect(Collectors.toList()); // 构建JWT Claims,写入权限 Instant now = Instant.now(); JwtClaimsSet claims = JwtClaimsSet.builder() .issuer("your-app") .issuedAt(now) .expiresAt(now.plus(1, ChronoUnit.HOURS)) .subject(authentication.getName()) .claim("authorities", authorities) // 将权限写入JWT .build(); String jwt = jwtEncoder.encode(JwtEncoderParameters.from(claims)).getTokenValue(); return ResponseEntity.ok(new JwtResponse(jwt)); }
2. 配置JWT权限转换器
Spring Security默认会从JWT的scope或scp字段提取权限,并自动添加SCOPE_前缀。如果你的权限存在于自定义字段(比如上面的authorities),需要自定义JwtAuthenticationConverter来正确解析:
@Bean public JwtAuthenticationConverter jwtAuthenticationConverter() { JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter(); // 设置从JWT的"authorities"字段提取权限 grantedAuthoritiesConverter.setAuthoritiesClaimName("authorities"); // 如果不需要前缀,清空默认的"SCOPE_"前缀 grantedAuthoritiesConverter.setAuthorityPrefix(""); JwtAuthenticationConverter converter = new JwtAuthenticationConverter(); converter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter); return converter; }
然后在SecurityFilterChain中配置这个转换器:
.oauth2ResourceServer(oauth2 -> oauth2 .jwt(jwt -> jwt .jwtAuthenticationConverter(jwtAuthenticationConverter()) ) )
3. 对齐权限规则与实际权限
- 如果数据库中用户权限是
USER,配置用.hasAuthority("USER") - 如果数据库中用户权限是
ROLE_USER,配置用.hasRole("USER")(hasRole会自动拼接ROLE_前缀)
内容的提问来源于stack exchange,提问作者thor
相关产品推荐
相关产品推荐

