Android端OAuth2对接Spring Boot服务端实现Token认证
我刚好做过类似的Spring Boot + Android Google OAuth2登录的场景,你的核心问题其实是完成「Android拿到Google IdToken后,和自有服务端完成身份校验并获取自有AccessToken」这一环,下面给你一步步拆解可运行的方案:
1. Android端:将Google IdToken发送到自有Spring Boot服务端
你已经能获取到Google的IdToken了,接下来需要把这个Token通过POST请求传给你的服务端接口。这里用Retrofit举例(OkHttp写法逻辑一致):
第一步:定义API接口与数据模型
// 替换为你的服务端基础地址 interface AuthApi { @POST("auth/google-login") suspend fun loginWithGoogle(@Body request: GoogleLoginRequest): Response<AuthResponse> } // 传给服务端的请求体 data class GoogleLoginRequest( val idToken: String ) // 服务端返回的响应模型(和React端拿到的结构保持一致) data class AuthResponse( val accessToken: String, val tokenType: String = "Bearer" )
第二步:在Google登录回调中发送请求
// 假设你已经通过Google Sign-In API拿到了idToken val idToken = account.idToken ?: return // 初始化Retrofit实例 val authApi = Retrofit.Builder() .baseUrl("https://your-domain.com/api/") .addConverterFactory(GsonConverterFactory.create()) .build() .create(AuthApi::class.java) // 协程中发送请求(避免阻塞主线程) CoroutineScope(Dispatchers.IO).launch { try { val response = authApi.loginWithGoogle(GoogleLoginRequest(idToken)) if (response.isSuccessful) { val authResponse = response.body() ?: return@launch // 将AccessToken保存到本地(建议用EncryptedSharedPreferences加密存储) saveAccessToken(authResponse.accessToken) // 登录成功,跳转到主页面 } else { // 处理登录失败,比如提示用户"登录验证失败" } } catch (e: Exception) { // 处理网络异常,比如无网络、连接超时等 } }
2. Spring Boot端:接收IdToken并完成身份校验 + 生成自有AccessToken
这一步是核心,你需要写一个自定义登录接口,验证Google IdToken的合法性,再生成和React端一致的AccessToken:
第一步:添加Google IdToken验证依赖
如果还没添加,在pom.xml(Maven)中引入:
<dependency> <groupId>com.google.api-client</groupId> <artifactId>google-api-client</artifactId> <version>1.34.1</version> </dependency>
第二步:编写登录控制器
@RestController @RequestMapping("/api/auth") public class AuthController { private final GoogleIdTokenVerifier verifier; private final JwtTokenProvider jwtTokenProvider; private final UserRepository userRepository; // 构造注入:配置Android应用的Google客户端ID(从Google Cloud Console获取) public AuthController(@Value("${google.android.client-id}") String androidClientId, JwtTokenProvider jwtTokenProvider, UserRepository userRepository) { GoogleIdTokenVerifier.Builder builder = new GoogleIdTokenVerifier.Builder(new NetHttpTransport(), JacksonFactory.getDefaultInstance()) .setAudience(Collections.singletonList(androidClientId)); this.verifier = builder.build(); this.jwtTokenProvider = jwtTokenProvider; this.userRepository = userRepository; } @PostMapping("/google-login") public ResponseEntity<AuthResponse> loginWithGoogle(@RequestBody GoogleLoginRequest request) { try { // 验证Google IdToken的合法性(自动校验签名、受众、过期时间等) GoogleIdToken idToken = verifier.verify(request.getIdToken()); if (idToken == null) { return ResponseEntity.badRequest().body(new AuthResponse(null, "无效的IdToken")); } // 提取Google用户信息 GoogleIdToken.Payload payload = idToken.getPayload(); String googleId = payload.getSubject(); String email = payload.getEmail(); String name = (String) payload.get("name"); String pictureUrl = (String) payload.get("picture"); // 查找或创建本地用户(和React端登录时的逻辑完全一致) User user = userRepository.findByGoogleId(googleId) .orElseGet(() -> { User newUser = new User(); newUser.setGoogleId(googleId); newUser.setEmail(email); newUser.setName(name); newUser.setAvatarUrl(pictureUrl); return userRepository.save(newUser); }); // 生成自有服务的AccessToken(复用React端的JWT生成逻辑) String accessToken = jwtTokenProvider.generateToken(user); return ResponseEntity.ok(new AuthResponse(accessToken, "Bearer")); } catch (Exception e) { return ResponseEntity.badRequest().body(new AuthResponse(null, "IdToken验证失败:" + e.getMessage())); } } // 内部DTO类 public static class GoogleLoginRequest { private String idToken; public String getIdToken() { return idToken; } public void setIdToken(String idToken) { this.idToken = idToken; } } public static class AuthResponse { private String accessToken; private String tokenType; public AuthResponse(String accessToken, String tokenType) { this.accessToken = accessToken; this.tokenType = tokenType; } public String getAccessToken() { return accessToken; } public String getTokenType() { return tokenType; } } }
第三步:确保JWT生成逻辑和React端一致
这里的JwtTokenProvider必须是你已经在React端登录流程中使用的类,保证签名密钥、过期时间、Claim字段等完全一致,这样服务端才能正常识别Android端携带的Token。
3. Android端:在后续请求中携带AccessToken
每次发送API请求时,自动在请求头中添加Authorization: Bearer <你的AccessToken>,还是用Retrofit举例:
// 创建带拦截器的OkHttpClient val okHttpClient = OkHttpClient.Builder() .addInterceptor { chain -> val originalRequest = chain.request() // 从本地获取保存的AccessToken val accessToken = getSavedAccessToken() // 构建带Authorization头的新请求 val newRequest = originalRequest.newBuilder() .header("Authorization", "Bearer $accessToken") .build() chain.proceed(newRequest) } .build() // 初始化业务API服务 val apiService = Retrofit.Builder() .baseUrl("https://your-domain.com/api/") .client(okHttpClient) .addConverterFactory(GsonConverterFactory.create()) .build() .create(YourBusinessApi::class.java)
重要注意事项
- 确保Google Cloud Console中,你的Android应用客户端ID已添加到OAuth 2.0授权列表,服务端配置的
google.android.client-id必须和这个ID完全一致。 - Android端存储AccessToken时,建议用EncryptedSharedPreferences或Jetpack Security加密,避免明文泄露。
- 测试时可以先通过Postman模拟发送IdToken请求,确认服务端接口正常返回AccessToken后,再在Android端调试。
内容的提问来源于stack exchange,提问作者Fily1212
相关产品推荐
相关产品推荐

