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

Spring Security JWT认证配置致Postman带Bearer令牌返回403错误

问题分析与解决方案

1. JWT有效性校验逻辑完全反转(核心问题)

在JwtService的isTokenValid方法中,令牌过期的判断逻辑写反了:

public boolean isTokenValid(String token, UserDetails userDetails) {
    final String username = extractUsername(token);
    // 错误:仅当令牌过期时才判定有效,与预期完全相反
    return(username.equals(userDetails.getUsername())) && isTokenExpired(token);
}

isTokenExpired方法返回true代表令牌已过期,当前逻辑导致只有过期的令牌才会被认为有效,未过期的合法令牌无法通过校验,进而无法设置认证上下文,触发403错误。

修复代码:

public boolean isTokenValid(String token, UserDetails userDetails) {
    final String username = extractUsername(token);
    // 修正为:用户名匹配 且 令牌未过期
    return(username.equals(userDetails.getUsername())) && !isTokenExpired(token);
}

2. 请求链执行逻辑遗漏

JwtAuthenticationFilter中,filterChain.doFilter(request, response)被嵌套在if(userEmail != null && ...)代码块内,导致当userEmail为空或已存在认证信息时,请求链无法继续执行,请求被拦截返回403。

修复代码:

@Override
protected void doFilterInternal(
        @NonNull HttpServletRequest request,
        @NonNull HttpServletResponse response,
        @NonNull FilterChain filterChain
) throws ServletException, IOException {
    final String authHeader = request.getHeader(AUTHORIZATION);
    final String jwt;
    final String userEmail;
    if(authHeader == null || !authHeader.startsWith("Bearer ")){
        filterChain.doFilter(request, response);
        return;
    }
    jwt = authHeader.substring(7);
    userEmail = jwtService.extractUsername(jwt);
    if(userEmail != null && SecurityContextHolder.getContext().getAuthentication() == null){
        UserDetails userDetails = this.userDetailsService.loadUserByUsername(userEmail);
        if(jwtService.isTokenValid(jwt, userDetails)){
            UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
                    userDetails,
                    null,
                    userDetails.getAuthorities()
            );
            authToken.setDetails(
                    new WebAuthenticationDetailsSource().buildDetails(request)
            );
            SecurityContextHolder.getContext().setAuthentication(authToken);
        }
    }
    // 确保所有分支都会执行请求链,避免请求被拦截
    filterChain.doFilter(request, response);
}

3. 额外检查项

  • 用户权限配置:确保User类正确实现UserDetails接口,且Role枚举实现GrantedAuthority:
    public enum Role implements GrantedAuthority {
        USER, ADMIN;
    
        @Override
        public String getAuthority() {
            return "ROLE_" + this.name();
        }
    }
    
    同时User类的getAuthorities()方法需返回权限集合:
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return Collections.singletonList(role);
    }
    
  • 令牌过期时间:当前令牌有效期为24分钟,测试时确保令牌未过期,可调整为1000 * 60 * 60 * 24(24小时)延长有效期。

内容的提问来源于stack exchange,提问作者Mr Williams

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 02:16:08