Spring Boot 自定义 JWT 过滤器不允许任何没有令牌的请求

Posted

技术标签:

【中文标题】Spring Boot 自定义 JWT 过滤器不允许任何没有令牌的请求【英文标题】:Spring boot custom JWT filter not allowing any request without token 【发布时间】:2021-03-30 23:54:46 【问题描述】:

我正在使用带有 Spring Boot 安全配置的自定义 JWT 过滤器来允许某些没有 JWT 令牌的 API 请求。但是 WebSecurity 配置中的 permitAll() 方法不起作用(不允许任何没有 JWT 的请求)。它会引发自定义 InvalidJwtException。我在这里缺少什么?我已经尝试了很多谷歌搜索,但没有成功。

WebSecurityConfig 类

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
class WebSecurityConfig(
    private val jwtTokenProvider: JwtTokenProvider,
    private val filterChainExceptionHandler: FilterChainExceptionHandler,
) : WebSecurityConfigurerAdapter() 

    override fun configure(http: HttpSecurity?) 

        http?.csrf()?.disable()
        http?.sessionManagement()?.sessionCreationPolicy(SessionCreationPolicy.STATELESS)

        http
            ?.authorizeRequests()
            ?.antMatchers("/api/v1/auth/signin")?.permitAll()
            ?.antMatchers("/api/v1/auth/checkEmailExist")?.permitAll()
            ?.anyRequest()?.authenticated()

        http
            ?.addFilterBefore(JwtTokenFilter(jwtTokenProvider), UsernamePasswordAuthenticationFilter::class.java)
            ?.addFilterBefore(filterChainExceptionHandler, JwtTokenFilter::class.java)

    

    @Bean
    fun passwordEncoder(): PasswordEncoder 
        return BCryptPasswordEncoder(10)
    

    @Bean
    override fun authenticationManagerBean(): AuthenticationManager 
        return super.authenticationManagerBean()
    

JwtTokenFilter 类

@Component
class JwtTokenFilter(
    private val jwtTokenProvider: JwtTokenProvider
) : OncePerRequestFilter() 

    override fun doFilterInternal(
        request: HttpServletRequest,
        response: HttpServletResponse,
        filterChain: FilterChain
    ) 
        try 
            val token = jwtTokenProvider.resolveToken(request)
            if (token != null && jwtTokenProvider.validateToken(token)) 
                val auth = jwtTokenProvider.getAuthentication(token)
                SecurityContextHolder.getContext().authentication = auth
            
         catch (e: InvalidJwtException) 
            SecurityContextHolder.clearContext()
            throw InvalidJwtException(e.message, e.httpStatus)
        
        filterChain.doFilter(request, response)
    

解析令牌函数


 fun resolveToken(req: HttpServletRequest): String? 
        val bearerToken = req.getHeader(AUTHORIZATION_HEADER)
        return if (bearerToken != null && bearerToken.startsWith(BEARER)) 
            bearerToken.substring(7)
         else 
            throw InvalidJwtException("Authorization token must be Bearer [token]", HttpStatus.FORBIDDEN)
        
 

【问题讨论】:

那是你自己的代码在做的事情,没有token的时候,抛出异常。因为这总是在任何规则检查之前执行,所以它总是会抛出这个异常。因此不要抛出异常。 这行不应该允许没有令牌的两个请求吗?因为它有 permitAll ()antMatchers("/api/v1/auth/signin")?.permitAll() antMatchers("/api/v1/auth/checkEmailExist")?.permitAll() 没有。无论它是谁,它总是可以访问。但是,确定谁需要身份验证并在评估 permitAll 之前调用。如果您想禁用所有过滤器(不推荐),请将网络安全配置为 ignore 某些 URL然而,这会禁用该 URL 的所有安全过滤器。 【参考方案1】:

您的令牌验证应排除身份验证 URL:

if (!request.getRequestURL().toString().contains("auth") || (token != null && jwtTokenProvider.validateToken(token))) 

您可以选择比我使用过的“auth”更好的字符串来识别排除的路径

【讨论】:

以上是关于Spring Boot 自定义 JWT 过滤器不允许任何没有令牌的请求的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot + Apache Shrio + JWT前后端分离项目

Spring boot + JWT 实现安全验证 ---auth0.jwt

spring boot 自定义过滤器链

添加自定义过滤器 Apache Shiro + Spring Boot

Spring/Boot - JWT 未在 GET 请求中获取

Spring Boot + Mongo + JWT