Spring Security AuthorizationFilter返回403:已登录用户遭访问拒绝
JWT认证后接口返回403权限拒绝问题排查与解决
问题背景
用JWT维持请求间的用户认证状态,注册、登录成功拿到Token后,访问没配置.permitAll()的接口,明明用户有对应权限,AuthorizationFilter还是返回403拒绝访问。试过把hasAuthority换成hasRole,角色改成USER(不用ROLE_USER),但问题没解决。
使用版本:
- Spring Boot 3.0.5
- Spring Security 2.3.3(注:Spring Boot 3.x对应Spring Security 6.x版本,大概率是版本号写错了,版本不匹配也可能导致权限逻辑异常,建议先确认版本一致性)
排查方向与解决办法
1. 检查JWT过滤器的权限注入逻辑
JWTAuthenticationFilter解析Token后,必须把用户权限正确注入到Authentication对象中,否则Spring Security会判定用户无权限:
- 确认从Token中提取的权限列表已正确转换为
GrantedAuthority集合,示例写法:
// 从Token中获取权限列表,比如["ROLE_USER"] List<String> authorities = jwtTokenUtil.getAuthoritiesFromToken(token); Collection<GrantedAuthority> grantedAuthorities = authorities.stream() .map(SimpleGrantedAuthority::new) .collect(Collectors.toList()); // 构建Authentication对象并写入SecurityContext UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, null, grantedAuthorities); authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(authentication);
2. 匹配Spring Security 6.x的权限配置语法
Spring Boot 3.x搭配的Spring Security 6.x对权限规则做了调整:
- 用
hasRole("USER")时,框架会自动给权限加ROLE_前缀,所以Token中的权限必须是ROLE_USER; - 用
hasAuthority("USER")时,Token中的权限需严格匹配USER,不能加前缀; - 对照SecurityConfig中的规则和Token权限是否一致,示例:
// 若Token权限是ROLE_USER,用hasRole .authorizeHttpRequests(auth -> auth .requestMatchers("/api/protected/**").hasRole("USER") .anyRequest().permitAll() ) // 若Token权限是USER,用hasAuthority .authorizeHttpRequests(auth -> auth .requestMatchers("/api/protected/**").hasAuthority("USER") .anyRequest().permitAll() )
3. 确认过滤器顺序是否正确
JWTAuthenticationFilter必须放在UsernamePasswordAuthenticationFilter之前,保证请求先完成JWT解析,再进入权限校验环节:
@Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .csrf(csrf -> csrf.disable()) .authorizeHttpRequests(auth -> auth // 配置你的权限规则 ) .addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); return http.build(); }
4. 检查Token的携带格式
请求时必须按规范在请求头携带Token,格式为Authorization: Bearer <你的Token>,JWT过滤器需正确解析该格式:
String header = request.getHeader("Authorization"); if (header == null || !header.startsWith("Bearer ")) { filterChain.doFilter(request, response); return; } String token = header.substring(7); // 去除"Bearer "前缀
5. 排查SecurityContext持久化问题
Spring Boot 3.x默认使用DelegatingSecurityContextRepository,无状态认证场景下,需确保每次请求都重新解析Token并设置SecurityContext,不要依赖Session存储认证信息。
内容的提问来源于stack exchange,提问作者Wolf Ganger
相关产品推荐
相关产品推荐

