使用OncePerRequestFilter实现自定义身份验证会导致spring将所有异常映射到403

问题描述 投票:0回答:1

这是我的代码

package com.fnot.backend.config.spring.security

import com.fnot.backend.config.external.telegram.TelegramConfig
import com.fnot.backend.domain.external.telegram.bot.service.TelegramBotService
import jakarta.servlet.FilterChain
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.stereotype.Component
import org.springframework.web.filter.OncePerRequestFilter

@Component
class TelegramAuthenticationFilter(
    telegramConfig: TelegramConfig,
    private val telegramBotService: TelegramBotService
): OncePerRequestFilter() {

    private val botToken = telegramConfig.botToken

    override fun doFilterInternal(
        request: HttpServletRequest,
        response: HttpServletResponse,
        filterChain: FilterChain
    ) {
        val authHeader = request.getHeader("TG-Authorization")
        if(authHeader == null)  {
            filterChain.doFilter(request, response)
            return
        }

        val tmaAuthData = TmaAuthData(authHeader, botToken)

        if (tmaAuthData.isValid()) {
            val telegramUserData = tmaAuthData.getTelegramUserData()
            val user = telegramBotService.registerOrUpdateUserTma(telegramUserData)

            val authToken = TelegramAuthenticationToken(user.id!!)
            SecurityContextHolder.getContext().authentication = authToken
        }

        filterChain.doFilter(request, response)
    }
}

它的作用:

  1. 从标头获取一些数据
  2. 通过将 auth 对象放入安全上下文中来使用它来验证用户

问题是什么: 我注意到,如果 spring 抛出异常(例如在数据库中找不到行),那么它不会像通常那样映射到

500
响应代码,而是映射到
403

问题: 如何更改过滤器,以便 Spring 不会将任意未处理的异常映射到

403
,而是将它们映射到
500

这是我的

SecurityConfig

package com.fnot.backend.config.spring.security

import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.web.SecurityFilterChain
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
import org.springframework.web.cors.CorsConfiguration
import org.springframework.web.cors.UrlBasedCorsConfigurationSource
import org.springframework.web.filter.CorsFilter

@Configuration
@EnableWebSecurity
class SecurityConfig(
    private val telegramAuthenticationFilter: TelegramAuthenticationFilter
) {
    @Bean
    fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
        http
            .csrf { it.disable() }
            .cors {  } // Enable CORS
            .authorizeHttpRequests { auth ->
                auth.requestMatchers("/").permitAll()
                .anyRequest().authenticated()
            }
            .addFilterBefore(telegramAuthenticationFilter, UsernamePasswordAuthenticationFilter::class.java)

        return http.build()
    }

    @Bean
    fun corsFilter(): CorsFilter {
        val source = UrlBasedCorsConfigurationSource()
        val config = CorsConfiguration()

        config.allowCredentials = true
        config.addAllowedOriginPattern("*") // Allow all origins
        config.addAllowedHeader("*") // Allow all headers
        config.addAllowedMethod("*") // Allow all methods

        source.registerCorsConfiguration("/**", config)
        return CorsFilter(source)
    }
}

我尝试调试

ExceptionTranslationFilter
,它首先将异常捕获为
ServletException
,并以底层业务逻辑异常为原因(例如未找到数据库中的行),但随后当它进一步处理时,它会得到一个
AccessDeniedExceptionThrown 
来自
AuthorizationFilter
doFilterMethod()

spring spring-boot spring-security
1个回答
0
投票

解决方案如下。这就像 Spring Security 6 的一个非常意想不到的新功能什么的。我自己很难弄清楚。

Spring:REST 异常被捕获为 403 禁止异常

© www.soinside.com 2019 - 2024. All rights reserved.