无法从SecurityFilterChain中排除已定义的URL

gojuced7  于 2023-10-20  发布在  Spring
关注(0)|答案(1)|浏览(136)

我正在做一个spring-boot 3项目,并为授权过程添加了spring-security 6。由于它在头中使用Authorization令牌,因此我希望不使用Authorization令牌,例如/health或/signup
首先,我写了SecurityConfig

@Configuration
@EnableWebSecurity
@Order(1)
class SecurityConfiguration(private val jwtFilter : JwtFilter) {
    @Bean
    fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http.csrf().disable().
        authorizeHttpRequests { authorize ->
            authorize
                .requestMatchers("/health").permitAll()
                .anyRequest().authenticated()
        }

        http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter::class.java)
        return http.build()
    }
}

这里是过滤器;

@Component
class JwtFilter : Filter {
    override fun doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain) {
        val httpRequest = request as HttpServletRequest
        val httpResponse = response as HttpServletResponse
        val jwt = httpRequest.getHeader("Authorization")?.removePrefix("Bearer ")
        if(jwt != null){
            val extractedToken = verifyJwtWithLambda(jwt)
            val isValid : Boolean? = extractedToken["isValid"] as? Boolean
            if(isValid!!){
                val attributes = extractedToken["attributes"] as? Map<*, *>
                val subject = attributes?.get("userId") as? String
                val authentication = UsernamePasswordAuthenticationToken(subject, null, emptyList())
                SecurityContextHolder.getContext().authentication = authentication
                chain.doFilter(request, response)
            }
            else {
                httpResponse.status = HttpServletResponse.SC_UNAUTHORIZED
            }
        }
        else {
                httpResponse.status = HttpServletResponse.SC_UNAUTHORIZED
        }
    }

现在,当我向/health发送get请求时,它返回401。但是当我发送带有授权令牌的请求时,它返回200。
到目前为止我尝试了什么?

  • 添加了WebSecurityCustomizer以忽略,不起作用。
  • 尝试.anonymous而不是. permit,但没有成功。
  • 添加了逻辑控制到JwtFilter来检查ServletPath中定义的URL,然后chain.doFilter,它可以工作,但我认为它不是可用的。
  • Spring Security permitAll not allowing anonymous access,尝试了此主题
  • 我试图改变addFilterBefore像addFilterAfter,没有工作.
  • 如果我用chain.doFilter()更改第二个Else块中的httpResponse.status = HttpServletResponse.SC_UNAUTHORIZED部分,它会像预期的那样工作,但返回403而不是401。

非常感谢。

oiopk7p5

oiopk7p51#

使用OncePerRequestFilter替代并重写shouldNotFilter方法并添加任何要排除的端点如何?我已经为一个单一的url添加了一个例子,但你可以维护一个列表,并排除这些端点。

@Component
class JwtFilter : OncePerRequestFilter {
    override fun doFilterInternal(request: ServletRequest, response: ServletResponse, chain: FilterChain) {
        val httpRequest = request as HttpServletRequest
        val httpResponse = response as HttpServletResponse
        val jwt = httpRequest.getHeader("Authorization")?.removePrefix("Bearer ")
        if (jwt != null) {
            val extractedToken = verifyJwtWithLambda(jwt)
            val isValid: Boolean? = extractedToken["isValid"] as? Boolean
            if (isValid!!) {
                val attributes = extractedToken["attributes"] as? Map<*, *>
                val subject = attributes?.get("userId") as? String
                val authentication = UsernamePasswordAuthenticationToken(subject, null, emptyList())
                SecurityContextHolder.getContext().authentication = authentication
                chain.doFilter(request, response)
            } else {
                httpResponse.status = HttpServletResponse.SC_UNAUTHORIZED
            }
        } else {
            httpResponse.status = HttpServletResponse.SC_UNAUTHORIZED
        }
    }

    override fun shouldNotFilter(request: HttpServletRequest): Boolean {
        val url = request.requestURL;
        return "/health".equals(url);
    }
}

参考文件:
Extends OncePerRequestFilter bypass specific URL
https://www.baeldung.com/spring-exclude-filter

相关问题