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

Spring Boot中permitAll接口调用成功却记录未授权错误的原因?

问题分析与解决方案

问题原因

当调用标记permitAll()的/api/v1/teams/**端点时,日志出现未授权错误但请求能正常返回的核心原因在于Spring Security过滤器链的执行逻辑:

  1. 自定义的AuthTokenFilter在AnonymousAuthenticationFilter之前执行,当请求无JWT时,不会向SecurityContext中写入任何认证信息。
  2. 后续的FilterSecurityInterceptor检查权限时,发现SecurityContext中无认证对象,抛出InsufficientAuthenticationException。
  3. ExceptionTranslationFilter捕获该异常后,因当前认证状态为null(而非标准匿名认证),会触发AuthEntryPointJwt记录错误日志。
  4. 由于HttpSecurity中配置了permitAll(),请求最终仍会被允许通过并返回正常响应,但错误日志已被记录。

解决方案

方式一:让AuthTokenFilter跳过无需认证的路径

修改AuthTokenFilter,重写shouldNotFilter方法,指定无需过滤的路径:

public class AuthTokenFilter extends OncePerRequestFilter {
    // ... 原有代码

    @Override
    protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
        String path = request.getServletPath();
        return path.startsWith("/api/v1/teams/");
    }
}

此方式下,/api/v1/teams/**的请求会跳过AuthTokenFilter,后续的AnonymousAuthenticationFilter会自动创建标准匿名认证,FilterSecurityInterceptor检查时不会抛出异常,避免错误日志。

方式二:在AuthTokenFilter中手动设置匿名认证

若不想跳过过滤,可在无JWT的请求中手动写入匿名认证信息到SecurityContext:

public class AuthTokenFilter extends OncePerRequestFilter {
    private static final String ANONYMOUS_USER = "anonymousUser";
    private static final List<GrantedAuthority> ANONYMOUS_AUTHORITIES = Collections.singletonList(new SimpleGrantedAuthority("ROLE_ANONYMOUS"));

    @Override
    protected void doFilterInternal(
            HttpServletRequest request,
            HttpServletResponse response,
            FilterChain filterChain
    ) throws ServletException, IOException {
        try {
            String jwt = parseJwt(request);
            if (jwt != null && jwtUtils.validateJwtToken(jwt)) {
                // 原有设置认证的逻辑
                String username = jwtUtils.getUserNameFromJwtToken(jwt);
                UserDetails userDetails = userDetailsService.loadUserByUsername(username);
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                        userDetails,
                        null,
                        userDetails.getAuthorities()
                );
                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(authentication);
            } else {
                // 手动设置匿名认证
                UsernamePasswordAuthenticationToken anonymousAuth = new UsernamePasswordAuthenticationToken(
                        ANONYMOUS_USER,
                        null,
                        ANONYMOUS_AUTHORITIES
                );
                anonymousAuth.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(anonymousAuth);
            }
        } catch (Exception e) {
            logger.error("Cannot set user authentication: {}", e);
        }
        filterChain.doFilter(request, response);
    }

    // ... 原有代码
}

这样FilterSecurityInterceptor检查时会识别到标准匿名认证,结合permitAll()配置,不会触发异常日志。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 01:20:22