You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 01:12:02