如何让OncePerRequestFilter过滤器跳过无需JWT验证的URL
解决方案
有两种常见方式可以让JwtFilter跳过无需验证的URL,以下是具体实现:
方案一:在JwtFilter内部添加路径忽略逻辑
直接在过滤器中判断请求路径是否属于无需验证的范围,若是则直接放行,不执行JWT验证逻辑:
import org.springframework.util.AntPathMatcher import javax.servlet.http.HttpServletRequest import javax.servlet.http.HttpServletResponse import org.springframework.web.filter.OncePerRequestFilter import io.jsonwebtoken.Jwts import java.util.Date import org.springframework.http.HttpHeaders class JwtFilter( private val securityProperties: SecurityProperties ) : OncePerRequestFilter() { companion object { const val PREFIX = "Bearer " // 定义需要忽略的URL模式 private val IGNORED_PATHS = listOf("/api/auth/**") private val PATH_MATCHER = AntPathMatcher() } override fun doFilterInternal( request: HttpServletRequest, response: HttpServletResponse, filterChain: FilterChain ) { // 检查当前请求是否匹配忽略路径,匹配则直接放行 val requestUri = request.requestURI if (IGNORED_PATHS.any { PATH_MATCHER.match(it, requestUri) }) { filterChain.doFilter(request, response) return } val token = resolvedToken(request) if (token.isEmpty()) throw InvalidTokenException try { val claims = Jwts.parser() .setSigningKey(securityProperties.key) .parseClaimsJws(token) val jwtBody = claims.body // 修正原代码笔误:jwtDody -> jwtBody val expiration = jwtBody.expiration if (expiration.before(Date())) { throw ExpiredTokenException } filterChain.doFilter(request, response) } catch (e: Exception) { throw InvalidTokenException } } private fun resolvedToken(request: HttpServletRequest): String { val bearerToken: String? = request.getHeader(HttpHeaders.AUTHORIZATION) bearerToken?.let { if (bearerToken.startsWith(PREFIX)) { return bearerToken.substring(PREFIX.length) } } return "" } }
方案二:在SecurityConfig中限定过滤器的拦截范围
通过Spring Security的配置,让JwtFilter仅对需要验证的URL生效,自然跳过无需JWT的路径:
import org.springframework.security.web.util.matcher.AntPathRequestMatcher import org.springframework.security.web.util.matcher.NegatedRequestMatcher import org.springframework.security.web.util.matcher.RequestMatcher @Configuration @EnableWebSecurity class SecurityConfig( val securityProperties: SecurityProperties ) { @Bean protected fun securityFilterChain(http: HttpSecurity): SecurityFilterChain { // 定义需要排除的请求匹配器 val ignoredRequestMatcher: RequestMatcher = NegatedRequestMatcher(AntPathRequestMatcher("/api/auth/**")) http .csrf().disable() .httpBasic().disable() .cors() .and() .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .authorizeRequests() .antMatchers("/api/auth/**").permitAll() .anyRequest().authenticated() // 补充其他路径需认证的规则 .and() // 仅对非/api/auth/**的请求应用JwtFilter .addFilterBefore(JwtFilter(securityProperties), UsernamePasswordAuthenticationFilter::class.java) .requestMatcher(ignoredRequestMatcher) return http.build() } @Bean protected fun passwordEncoder() = BCryptPasswordEncoder() }
两种方案对比
- 方案一:过滤器内部自主控制忽略路径,无需修改Security配置,适合忽略路径较少、规则简单的场景。
- 方案二:通过Security配置统一管理拦截范围,逻辑更清晰,适合复杂的路径匹配规则,符合Spring Security的配置习惯。
内容的提问来源于stack exchange,提问作者HamTory
相关产品推荐
相关产品推荐

