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

Spring Boot手动处理JWT:自定义OpenIdConnectFilter未触发求助

解决OpenIdConnectFilter未触发JWT验证的问题

我来帮你梳理下问题所在,你的过滤器没被调用、返回403,主要是配置上的几个细节没处理好,咱们一步步来修正:

1. 过滤器添加位置错误,导致未加入有效过滤器链

你现在用了addFilterAfter(OpenIdConnectFilter("/secure"), OpenIDAuthenticationFilter::class.java),但这里有个核心问题:如果OpenIDAuthenticationFilter本身没有被Spring Security加载到过滤器链中,addFilterAfter就找不到对应的前置过滤器,你的自定义过滤器自然不会被添加进去。

另外,你构造过滤器时指定的拦截路径是/secure,如果你的受保护请求不是指向这个路径(比如是/api/**或者其他业务路径),过滤器也不会触发。

修正方案:
把过滤器添加到UsernamePasswordAuthenticationFilter之前(这个过滤器是Spring Security默认存在的),同时根据你的实际需求设置拦截路径,比如拦截所有受保护请求可以用/**:

@Configuration @EnableWebSecurity 
class WebSecurityConfig : WebSecurityConfigurerAdapter() {

    @Throws(Exception::class)
    override fun configure(http: HttpSecurity) {
        http
            // 添加自定义过滤器到默认表单认证过滤器之前
            .addFilterBefore(openIdConnectFilter(), UsernamePasswordAuthenticationFilter::class.java)
            .authorizeRequests()
                .antMatchers("/", "/home").permitAll()
                .anyRequest().authenticated()
    }

    // 给自定义过滤器注入AuthenticationManager
    @Bean
    fun openIdConnectFilter(): OpenIdConnectFilter {
        val filter = OpenIdConnectFilter("/**")
        filter.setAuthenticationManager(authenticationManagerBean())
        return filter
    }
}

2. 自定义过滤器缺少AuthenticationManager配置

AbstractAuthenticationProcessingFilter的子类必须设置AuthenticationManager才能正常处理认证流程,否则即使过滤器被触发,也无法完成认证逻辑。上面的配置里已经通过filter.setAuthenticationManager(authenticationManagerBean())解决了这个问题。

3. 安全配置中重复的authorizeRequests导致配置覆盖

你原来的代码里写了两次.authorizeRequests(),这会导致第一次的配置被第二次覆盖,虽然这里不影响过滤器触发,但会导致权限配置异常,建议合并成一个统一的权限规则块。

4. 确保过滤器正确处理JWT请求

最后检查你的OpenIdConnectFilter实现,要确保它能从请求中正确提取JWT令牌(通常是从Authorization头的Bearer前缀后获取),并在attemptAuthentication方法中完成验证:

class OpenIdConnectFilter(defaultFilterProcessesUrl: String) : AbstractAuthenticationProcessingFilter(defaultFilterProcessesUrl) {

    // 替换成你的实际JWT密钥
    private val SECRET_KEY = "your-strong-secret-key-here"

    override fun attemptAuthentication(request: HttpServletRequest, response: HttpServletResponse): Authentication {
        // 从请求头获取JWT令牌
        val authHeader = request.getHeader("Authorization")
        if (authHeader == null || !authHeader.startsWith("Bearer ")) {
            throw BadCredentialsException("Missing or invalid Authorization header")
        }
        val token = authHeader.substring(7)

        // 解析并验证JWT签名和内容
        val claims = Jwts.parser()
            .setSigningKey(SECRET_KEY.toByteArray())
            .parseClaimsJws(token)
            .body

        // 从JWT中提取用户信息和权限列表
        val username = claims.subject
        val authorities = claims.get("authorities", List::class.java)
            .map { SimpleGrantedAuthority(it.toString()) }

        // 返回认证对象,后续Spring Security会自动处理会话
        return UsernamePasswordAuthenticationToken(username, null, authorities)
    }

    override fun successfulAuthentication(request: HttpServletRequest, response: HttpServletResponse, chain: FilterChain, authResult: Authentication) {
        // 将认证结果存入SecurityContext,后续请求会自动识别已认证用户
        SecurityContextHolder.getContext().authentication = authResult
        chain.doFilter(request, response)
    }
}

做完这些修改后,你的过滤器应该就能正常拦截请求并进行JWT验证了,记得测试时确保请求头里携带正确的Bearer <JWT_TOKEN>格式令牌。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:39:44