Spring Security 6 中正确排除特定 URL 的完整解决方案

胖伟姑娘_9618

胖伟姑娘_9618

2026-10-14

895人浏览

原创

Spring Security 6 中正确排除特定 URL 的完整解决方案

在 Spring Boot 3 + Spring Security 6 中,permitAll() 无法绕过自定义 JWT 过滤器导致认证失败时,需让过滤器主动跳过指定路径(如 /health),而非仅依赖 authorizeHttpRequests 配置。

在 spring boot 3 + spring security 6 中,`permitall()` 无法绕过自定义 jwt 过滤器导致认证失败时,需让过滤器主动跳过指定路径(如 `/health`),而非仅依赖 `authorizehttprequests` 配置。

问题根源在于:permitAll() 仅控制 授权决策链(AuthorizationManager) 的放行逻辑,但 Spring Security 的过滤器链(Filter Chain)是顺序执行的——你的 JwtFilter 会在 SecurityFilterChain 授权检查之前被调用。因此,即使 /health 被配置为 permitAll(),请求仍会先进入 JwtFilter,而该过滤器在无 Authorization 头时直接返回 401,根本未到达后续授权判断环节。

✅ 正确解法:让 JwtFilter 主动跳过无需认证的路径,而非依赖授权规则“事后放行”。

✅ 推荐方案:继承 OncePerRequestFilter 并重写 shouldNotFilter

OncePerRequestFilter 提供了 shouldNotFilter(HttpServletRequest) 钩子方法,专用于声明哪些请求不应经过该过滤器。这是 Spring Security 官方推荐的、语义清晰且线程安全的过滤器跳过方式。

即创
即创

即创是一款AI文本写作工具,抖音推出的一站式AI智能创作平台。

下载

以下是优化后的 JwtFilter 实现(Kotlin):

@Component
class JwtFilter : OncePerRequestFilter() {

    // 定义需跳过的免认证路径(支持通配符或正则可进一步扩展)
    private val excludedPaths = setOf("/health", "/signup", "/actuator/**")

    override fun shouldNotFilter(request: HttpServletRequest): Boolean {
        val path = request.servletPath
        return excludedPaths.any { pattern ->
            when {
                pattern.endsWith("/**") -> {
                    val prefix = pattern.substring(0, pattern.length - 3)
                    path.startsWith(prefix)
                }
                else -> path == pattern
            }
        }
    }

    override fun doFilterInternal(
        request: ServletRequest,
        response: ServletResponse,
        chain: FilterChain
    ) {
        val httpRequest = request as HttpServletRequest
        val httpResponse = response as HttpServletResponse

        // ✅ 此处已确保非 excludedPaths 请求才进入校验逻辑
        val jwt = httpRequest.getHeader("Authorization")?.removePrefix("Bearer ")
        if (jwt != null) {
            val extractedToken = verifyJwtWithLambda(jwt)
            val isValid = extractedToken["isValid"] as? Boolean ?: false
            if (isValid) {
                val attributes = extractedToken["attributes"] as? Map
                val subject = attributes?.get("userId") as? String
                val auth = UsernamePasswordAuthenticationToken(subject, null, emptyList())
                SecurityContextHolder.getContext().authentication = auth
                chain.doFilter(request, response)
            } else {
                httpResponse.status = HttpServletResponse.SC_UNAUTHORIZED
            }
        } else {
            httpResponse.status = HttpServletResponse.SC_UNAUTHORIZED
        }
    }
}

⚠️ 关键注意事项

  • 不要移除 @Order 或随意调整过滤器顺序:addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter::class.java) 是合理的位置(在认证过滤器之前注入凭证),但跳过逻辑必须由过滤器自身控制,而非靠顺序规避。
  • 避免在 doFilter 中手动 chain.doFilter() 代替拒绝:如原问题中“改为 chain.doFilter() 得到 403”,是因为跳过 JWT 校验后,请求继续执行但未设置 Authentication,最终被 authorizeHttpRequests 的 .anyRequest().authenticated() 拦截为 403(访问被拒绝),而非 401(未认证)。正确做法是 让过滤器不执行任何逻辑并透传(via shouldNotFilter)。
  • WebSecurityCustomizer.ignore() 已弃用/不适用:Spring Security 6 中 WebSecurity(旧模式)已被废弃,ignore() 对基于 SecurityFilterChain 的新模型完全无效,切勿尝试。
  • 路径匹配建议:生产环境建议使用 AntPathMatcher 或 PathPatternParser 做更健壮的路径匹配(如支持 /**、/api/v1/**),上例中已给出简易通配符实现,可根据需要升级。

✅ 补充:SecurityConfiguration 可保持简洁(推荐)

@Configuration
@EnableWebSecurity
class SecurityConfiguration(
    private val jwtFilter: JwtFilter
) {
    @Bean
    fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            csrf { disable() }
            authorizeHttpRequests {
                authorize("/health", permitAll)
                authorize("/signup", permitAll)
                authorize(anyRequest, authenticated)
            }
            addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter::class.java)
        }
        return http.build()
    }
}

至此,/health 和 /signup 请求将完全绕过 JwtFilter,直接交由 Spring Security 授权决策(permitAll 生效),返回 200;其他路径则正常执行 JWT 解析与认证。逻辑清晰、职责分明,符合 Spring Security 6 最佳实践。

相关专题

更多
spring框架介绍
spring框架介绍

本专题整合了spring框架相关内容,想了解更多详细内容,请阅读专题下面的文章。

2025.08.06

2511

22

Java Spring Security 与认证授权
Java Spring Security 与认证授权

本专题系统讲解 Java Spring Security 框架在认证与授权中的应用,涵盖用户身份验证、权限控制、JWT与OAuth2实现、跨站请求伪造(CSRF)防护、会话管理与安全漏洞防范。通过实际项目案例,帮助学习者掌握如何 使用 Spring Security 实现高安全性认证与授权机制,提升 Web 应用的安全性与用户数据保护。

2026.01.26

457

25

Python uv使用教程
Python uv使用教程

本专题汇总了 Python uv 使用教程与高效使用指南,从 uv 安装配置、常用命令到虚拟环境、依赖管理与项目打包,系统讲解如何用 uv 替代 pip 与 poetry,全面提升 Python 项目开发效率,助你快速上手这一现代化包管理工具,打造干净高效的 Python 工作流。

2026.10.15

0

15

剧云AI短剧创作教程合集
剧云AI短剧创作教程合集

本专题聚焦剧云AI短剧创作,讲解从短剧灵感、梗概、全局大纲到分集、分场和正文的完整流程及节奏设计方法。

2026.10.14

0

15

剧云AI剧本创作零基础入门
剧云AI剧本创作零基础入门

本专题系统讲解剧云AI剧本创作流程,涵盖灵感、梗概、大纲、分场与正文生成,帮助新手快速完成首个中文剧本项目。

2026.10.14

0

14

VibeKnow文档转视频操作指南
VibeKnow文档转视频操作指南

本专题讲解VibeKnow上传Word、TXT、Markdown等材料生成视频的方法,覆盖内容解析、脚本组织、画面生成与成片检查。

2026.10.14

0

15

VibeKnow知识视频制作与导出详解
VibeKnow知识视频制作与导出详解

本专题整理VibeKnow从注册、素材上传、AI生成到预览导出的完整操作,帮助新手快速制作第一条知识讲解视频。

2026.10.14

0

13

二狗PPT大纲编辑实操指南
二狗PPT大纲编辑实操指南

本专题聚焦二狗PPT结构化大纲的生成和修改,讲解标题、正文、目录、页数与页面顺序的调整方法,提升汇报逻辑和内容完整性。

2026.10.14

0

15

二狗PPT文档转PPT全教程
二狗PPT文档转PPT全教程

本专题讲解二狗PPT解析Word、PDF、Excel和PPT资料的方法,涵盖文件上传、内容提取、大纲整理、异常处理与转换后校对。

2026.10.14

0

13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.7万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133.7万人学习