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

Spring Security自定义Firebase AuthenticationProvider未执行问题求助

问题分析与解决方案

你的自定义Firebase认证提供者未被触发、受保护路由返回403的核心原因有三个:

  1. 缺少Token提取过滤器:Spring Security默认不会自动处理Bearer Token,没有过滤器将请求中的Token转换成Authentication对象,导致自定义Provider根本不会被调用。
  2. Provider的supports匹配错误:当前supports方法匹配UsernamePasswordAuthenticationToken,但这类Token是用于用户名密码认证的,和Bearer Token场景不匹配。
  3. 角色前缀缺失:Spring Security的hasRole方法会自动给角色名添加ROLE_前缀,你的代码中生成的SimpleGrantedAuthority没有加该前缀,导致权限校验失败。

修复步骤

1. 添加Bearer Token提取过滤器

创建一个过滤器,从请求头中提取Firebase的Bearer Token,并生成对应的Authentication对象交给认证管理器处理:

@Component
class FirebaseTokenFilter : OncePerRequestFilter() {
    @Autowired
    lateinit var authenticationManager: AuthenticationManager

    override fun doFilterInternal(
        request: HttpServletRequest,
        response: HttpServletResponse,
        filterChain: FilterChain
    ) {
        val authHeader = request.getHeader("Authorization")
        if (!authHeader.isNullOrBlank() && authHeader.startsWith("Bearer ")) {
            val token = authHeader.substring(7)
            // 生成预认证对象,将Token作为凭证传递
            val preAuthToken = PreAuthenticatedAuthenticationToken(null, token)
            // 触发认证流程
            val authenticated = authenticationManager.authenticate(preAuthToken)
            SecurityContextHolder.getContext().authentication = authenticated
        }
        filterChain.doFilter(request, response)
    }
}

2. 修改FirebaseAuthenticationProvider

调整supports方法匹配的Authentication类型,并修正角色前缀:

@Component
class FirebaseAuthenticationProvider(private val userService: UserService): AuthenticationProvider {

    override fun authenticate(authentication: Authentication?): Authentication {
        val token = authentication?.credentials as? String ?: throw BadCredentialsException("No Token Supplied!")
        val decoded = userService.decodeToken(token)

        val uid = decoded.uid
        val email = decoded.email ?: "" // 处理email可能为null的情况
        // 给角色添加ROLE_前缀,适配Spring Security的hasRole规则
        val roles = Role
            .claimsToRoles(decoded.claims)
            .map { SimpleGrantedAuthority("ROLE_${it.name}") }

        val userDetails = User(uid, email, roles)
        return UsernamePasswordAuthenticationToken(userDetails, token, roles)
    }

    override fun supports(authentication: Class<*>): Boolean {
        // 匹配预认证Token类型,和过滤器生成的对象一致
        return PreAuthenticatedAuthenticationToken::class.java.isAssignableFrom(authentication)
    }
}

3. 更新SecurityConfig配置

将自定义过滤器加入过滤链,并配置认证管理器:

@Configuration
class SecurityConfig(
    private val authenticationProvider: FirebaseAuthenticationProvider,
    private val firebaseTokenFilter: FirebaseTokenFilter
) {

    @Bean
    fun filterChain(http: HttpSecurity): SecurityFilterChain {
        return http
            .authorizeHttpRequests()
                .requestMatchers("/api/v1/*/create", "/api/v1/*/update", "/api/v1/*/delete").hasAnyRole("EDITOR", "ADMINISTRATOR")
                .requestMatchers("/api/v1/users/**").hasRole("ADMINISTRATOR")
                .anyRequest().permitAll()
            .and()
                .csrf().disable()
                .authenticationProvider(authenticationProvider)
                // 将自定义过滤器添加到用户名密码过滤器之前
                .addFilterBefore(firebaseTokenFilter, UsernamePasswordAuthenticationFilter::class.java)
            .build()
    }

    // 配置认证管理器,注册自定义Provider
    @Bean
    fun authenticationManager(authBuilder: AuthenticationManagerBuilder): AuthenticationManager {
        authBuilder.authenticationProvider(authenticationProvider)
        return authBuilder.build()
    }
}

额外注意事项

  • 确保userService.decodeToken方法正确验证Firebase Token的有效性,建议使用Firebase官方SDK的FirebaseAuth.getInstance().verifyIdToken(token)方法,避免手动解析导致的安全问题。
  • 测试时确认请求头中携带的是Authorization: Bearer <your-firebase-token>格式的Token。

内容的提问来源于stack exchange,提问作者Smilin' Dominator

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 09:35:29