Go(Gin-Gonic/Gothic)后端对接React Native Expo登录回调跳转问题
解决React Native Expo客户端对接Go后端谷歌登录回调跳转问题
核心思路
Expo客户端无法直接接收Web端的回调请求,需要通过**深链接(Deep Linking)**将登录结果(JWT)从后端传递回客户端。调整后端回调逻辑,将原本返回JSON的方式改为重定向到客户端深链接并携带JWT;客户端使用Expo Auth Session或Linking API监听深链接,完成登录状态同步。
一、后端Go代码调整
1. 修改回调函数CompleteAuth
将原本返回JSON的逻辑改为重定向到客户端深链接,把JWT作为查询参数传递(生产环境建议用临时存储+短码替代直接传token,避免暴露风险,以下为演示示例):
func (auth *AuthAPI) CompleteAuth(c *gin.Context) { q := c.Request.URL.Query() provider := c.Param("provider") q.Add("provider", provider) c.Request.URL.RawQuery = q.Encode() user, err := gothic.CompleteUserAuth(c.Writer, c.Request) if err != nil { c.AbortWithError(http.StatusInternalServerError, err) return } // 原有用户注册/查询逻辑保持不变 var user_id = user.UserID var user_provider = user.Provider count := auth.database_connection.QueryRow("SELECT COUNT(*) FROM auth WHERE id = $1 AND method = $2", user_id, user_provider) var user_count int err = count.Scan(&user_count) if err != nil { c.AbortWithStatus(http.StatusNotFound) slog.Warn("User not found", "user", user_id, "err", err) return } if user_count == 0 { var new_user_id int err := auth.database_connection.QueryRow("INSERT INTO users (username, email) VALUES ($1, $2) RETURNING id", user.Name, user.Email).Scan(&new_user_id) if err != nil { c.AbortWithError(http.StatusInternalServerError, err) return } _, err = auth.database_connection.Exec("INSERT INTO auth (id, method, user_id) VALUES ($1, $2, $3)", user_id, user_provider, new_user_id) if err != nil { c.AbortWithError(http.StatusInternalServerError, err) return } } // 生成JWT token, err := generateJWT(user.UserID) if err != nil { c.AbortWithError(http.StatusInternalServerError, err) return } // 定义客户端深链接(需提前配置Expo的scheme) // 示例scheme:myapp://auth/callback clientRedirectUrl := fmt.Sprintf("myapp://auth/callback?token=%s", token) // 重定向到客户端深链接 c.Redirect(http.StatusFound, clientRedirectUrl) }
2. 确认Gothic回调配置
确保Gothic初始化时,谷歌OAuth的回调地址已设置为后端的/login/google/callback(原有配置正常则无需修改)。
二、React Native Expo客户端实现
1. 配置深链接Scheme
在app.json中添加自定义scheme:
{ "expo": { "scheme": "myapp", // 其他项目配置... } }
2. 实现登录流程与回调监听
先安装依赖:
npx expo install expo-auth-session expo-web-browser
编写登录页面代码:
import React, { useEffect, useState } from 'react'; import { Button, View, Text } from 'react-native'; import * as WebBrowser from 'expo-web-browser'; import * as Linking from 'expo-linking'; // 替换为你的后端实际地址 const BACKEND_BASE_URL = 'http://your-backend-domain.com'; export default function LoginScreen() { const [token, setToken] = useState(null); // 从后端获取谷歌登录跳转URL const getAuthUrl = async () => { const response = await fetch(`${BACKEND_BASE_URL}/login/google`); const data = await response.json(); return data.redirectUrl; }; // 监听深链接回调,解析token useEffect(() => { const handleDeepLink = async (event) => { const urlParams = new URLSearchParams(event.url.split('?')[1]); const loginToken = urlParams.get('token'); if (loginToken) { setToken(loginToken); // 这里可将token存入AsyncStorage,再跳转到首页 console.log('登录成功,token:', loginToken); } }; // 监听实时深链接 Linking.addEventListener('url', handleDeepLink); // 检查App启动时的初始深链接(比如从浏览器跳转回来的场景) Linking.getInitialURL().then(url => url && handleDeepLink({ url })); return () => Linking.removeEventListener('url', handleDeepLink); }, []); // 触发登录流程 const handleGoogleLogin = async () => { const authUrl = await getAuthUrl(); await WebBrowser.openAuthSessionAsync(authUrl); }; return ( <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> {token ? ( <Text>登录成功!</Text> ) : ( <Button title="使用谷歌登录" onPress={handleGoogleLogin} /> )} </View> ); }
关键注意事项
- 生产环境安全:不要直接在URL中传递JWT,建议后端生成临时短码,客户端拿到短码后再请求后端换取JWT,降低泄露风险。
- 谷歌OAuth配置:确保谷歌开发者控制台中,已将后端
/login/google/callback添加到授权回调地址列表。 - 深链接测试:Expo开发环境可使用
npx expo start --dev-client测试,真机需用Expo Go扫码或打包测试。
内容的提问来源于stack exchange,提问作者Margin Petrisor-Victor
相关产品推荐
相关产品推荐

