Spring Security自定义Firebase AuthenticationProvider未执行问题求助
问题分析与解决方案
你的自定义Firebase认证提供者未被触发、受保护路由返回403的核心原因有三个:
- 缺少Token提取过滤器:Spring Security默认不会自动处理Bearer Token,没有过滤器将请求中的Token转换成Authentication对象,导致自定义Provider根本不会被调用。
- Provider的supports匹配错误:当前supports方法匹配
UsernamePasswordAuthenticationToken,但这类Token是用于用户名密码认证的,和Bearer Token场景不匹配。 - 角色前缀缺失: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
相关产品推荐
相关产品推荐

