Firebase Auth 是 Google 提供的托管认证服务,客户端可以通过邮箱密码、手机号验证码、Google 登录、Apple 登录甚至匿名方式完成身份认证。对后端来说,最关心的问题只有一个:怎么确认请求带来的用户身份是真的?答案就是校验客户端传来的 ID Token。这篇文章就以 Spring Boot 为例,完整走一遍整合流程,从依赖配置到接口鉴权,把关键代码和容易踩的坑都讲清楚。

一、整体认证流程与准备工作
先理清整个链路:移动端(Android 或 iOS)调用 Firebase SDK 完成登录,拿到一条 JWT 格式的 ID Token;之后每次请求后端接口,客户端在 HTTP 头里带上这条 Token;Spring Boot 这边用 Firebase Admin SDK 校验 Token 的签名和有效期,校验通过后取出其中的 uid 和 email 等字段,再映射到本地数据库的用户记录,最后放入 SecurityContext 供业务代码使用。
准备工作有两块。第一块是 Firebase 控制台侧:创建一个项目,开启需要的登录方式(比如邮箱、手机号、Google),然后在项目设置里生成服务账号的私钥文件,下载后是一个 JSON 文件。第二块是服务端侧:确保项目使用 JDK 8 或以上版本,准备一个普通的 Spring Boot 工程,引入 Web 和 Security 依赖即可。
需要注意的是,服务账号 JSON 文件等同于管理员权限,绝对不能打进客户端包或者提交到 Git 仓库,推荐通过环境变量指定文件路径,或者放在服务器上固定目录。下面是环境变量方式的示例:
# Linux / Mac export GOOGLE_APPLICATION_CREDENTIALS=/opt/secrets/firebase-service-account.json # Windows PowerShell $env:GOOGLE_APPLICATION_CREDENTIALS="C:\secrets\firebase-service-account.json"
二、引入依赖并初始化 Firebase Admin SDK
Firebase Admin SDK 在 Maven 中央仓库就有,直接在 pom.xml 中添加即可。注意不要去引老的 google-api-client 老一套依赖,Admin SDK 内部已经封装好了网络请求和证书校验逻辑:
<dependency>
<groupId>com.google.firebase</groupId>
<artifactId>firebase-admin</artifactId>
<version>9.2.0</version>
</dependency>
接着写一个配置类,在应用启动时初始化 FirebaseApp。这里通过 FirebaseOptions 指定凭据,如果同一个 JVM 里初始化过就跳过,避免重复初始化报错:
@Configuration
public class FirebaseConfig {
@PostConstruct
public void initFirebase() throws IOException {
if (FirebaseApp.getApps().isEmpty()) {
InputStream serviceAccount =
getClass().getResourceAsStream("/firebase-service-account.json");
FirebaseOptions options = FirebaseOptions.builder()
.setCredentials(GoogleCredentials.fromStream(serviceAccount))
.build();
FirebaseApp.initializeApp(options);
}
}
}
如果把 JSON 文件放到了 src/main/resources 下,上面的写法可以直接工作,但前面提过,密钥进仓库有泄漏风险,生产环境更推荐 GoogleCredentials.getApplicationDefault(),它会自动读取 GOOGLE_APPLICATION_CREDENTIALS 环境变量指向的文件,代码里完全不出现路径。
三、编写 Token 校验过滤器并接入 Spring Security
核心校验只靠一个 FirebaseAuth.getInstance().verifyIdToken(token) 调用,它内部会完成签名验证、过期检查、受众检查这三件事。先定义一个过滤器,从请求头解析 Token 并构建认证对象:
public class FirebaseTokenFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain) throws ServletException, IOException {
String header = request.getHeader("Authorization");
if (header != null && header.startsWith("Bearer ")) {
String token = header.substring(7);
try {
FirebaseToken decoded = FirebaseAuth.getInstance().verifyIdToken(token);
// uid 是 Firebase 侧的用户唯一标识
UsernamePasswordAuthenticationToken auth =
new UsernamePasswordAuthenticationToken(
decoded.getUid(), null, Collections.emptyList());
SecurityContextHolder.getContext().setAuthentication(auth);
} catch (FirebaseAuthException e) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid token");
return;
}
}
chain.doFilter(request, response);
}
}
然后把这个过滤器挂到 Spring Security 的过滤链中,放在 UsernamePasswordAuthenticationFilter 之前,并配置放行路径。这样所有需要登录的接口,只要请求头带了合法 Token,Controller 里就能直接通过 Authentication 拿到 uid:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf(AbstractHttpConfigurer::disable)
.sessionManagement(s ->
s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public/**").permitAll()
.anyRequest().authenticated())
.addFilterBefore(new FirebaseTokenFilter(),
UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
有一点值得强调:整合 Firebase 之后务必把会话策略设成 STATELESS,因为整个认证体系是无状态的 JWT 模式,如果还保留默认的 Session,既浪费内存,也可能造成安全上意想不到的会话残留问题。
四、用户映射、异常处理与常见坑
Firebase 只负责“证明你是谁”,业务数据还是存在自己的数据库里。常见做法是第一次校验通过时,按 uid 查本地用户表,查不到就自动注册一条新记录,把 uid、email、phone 等字段落库,伪代码如下:
@Service
public class UserService {
public AppUser resolveUser(FirebaseToken token) {
return userRepository.findByFirebaseUid(token.getUid())
.orElseGet(() -> {
AppUser user = new AppUser();
user.setFirebaseUid(token.getUid());
user.setEmail(token.getEmail());
user.setDisplayName(token.getName());
return userRepository.save(user);
});
}
}
异常处理上要区分几种情况:FirebaseAuthException 的错误码如果带 expired-ID-token,说明 Token 已过期,客户端应刷新后重试;invalid-ID-token 一般是 Token 被篡改或跨项目混用了,要检查客户端初始化的 GoogleService-Info.plist 或 google-services.json 是否和服务端属于同一个 Firebase 项目。排查跨项目问题时,可以打印 Token 的第一段做 base64 解码,看 aud 字段是否等于你的项目 ID。
还有几个容易忽视的坑:一是 Admin SDK 启动时会拉取 Google 的公钥,服务器如果处于内网环境需要配置代理,否则校验会一直失败;二是 ID Token 默认一小时过期,客户端务必使用 SDK 提供的 getIdToken(true) 强制刷新,而不是缓存旧值;三是如果业务有多个客户端(App 和小程序),建议校验时传入受众参数做二次确认。整体来说,这套方案的维护成本远低于自建认证系统,配合 Spring Security 的过滤器机制,几百行代码就能搭出一套稳定可靠的移动端登录体系。
Spring BootFirebase Auth移动端认证修改时间:2026-09-07 14:50:45