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

React Native(Expo)结合Node.js实现Google登录的正确流程咨询

Expo + Node.js 集成Google登录的正确方案

一、项目结构建议

后端(Node.js)结构

  • src/
    • config/:存放Google OAuth配置(客户端ID、客户端密钥、JWT密钥)
    • routes/:处理登录相关路由(如/api/auth/google)
    • services/:封装Google Token验证、用户逻辑(如googleAuthService.js)
    • middleware/:可选,JWT验证中间件,用于后续API接口鉴权
    • server.js:服务启动入口

前端(Expo)结构

  • components/:登录按钮组件(如GoogleLoginButton.js)
  • utils/:封装本地存储、请求工具
  • screens/:登录页面、首页等业务页面

二、安全的登录流程

  1. 客户端触发Google授权:通过expo-auth-session获取授权ID Token(而非直接拉取用户信息)
  2. 客户端将ID Token发送至Node.js后端
  3. 后端调用Google官方验证接口,校验ID Token的合法性(确保Token未被篡改、属于你的应用)
  4. 后端验证通过后,生成自身业务的JWT令牌返回给客户端,后续客户端用该JWT访问你的API
  5. 可选:后端根据Google返回的用户信息,创建/更新本地用户数据库记录

三、代码实现示例

前端(Expo)调整

import * as Google from "expo-auth-session/providers/google";
import { View, Button } from 'react-native';
import axios from 'axios';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { useEffect } from 'react';

export default function GoogleLoginButton() {
  const [request, response, promptAsync] = Google.useAuthRequest({
    androidClientId: "xxxxx.apps.googleusercontent.com",
    iosClientId: "xxxxx.apps.googleusercontent.com",
    // 指定获取ID Token,必须配置该参数
    responseType: Google.ResponseType.IdToken,
    // 按需添加需要获取的用户信息权限
    scopes: ['profile', 'email'],
  });

  useEffect(() => {
    if (response?.type === 'success') {
      const { id_token } = response.params;
      // 将ID Token发送到后端验证
      axios.post('http://你的后端地址/api/auth/google', { idToken: id_token })
        .then(res => {
          // 保存后端返回的JWT到本地
          AsyncStorage.setItem('userToken', res.data.token);
          // 跳转至首页或其他业务页面
        })
        .catch(err => {
          console.error('登录验证失败', err);
        });
    }
  }, [response]);

  return (
    <View>
      <Button 
        title="Google登录" 
        onPress={() => promptAsync()}
        disabled={!request}
      />
    </View>
  );
}

后端(Node.js)实现

先安装依赖:npm install google-auth-library jsonwebtoken express cors

1. 配置文件(src/config/google.js)

module.exports = {
  clientId: '你的Google客户端ID(与前端一致)',
  clientSecret: '你的Google客户端密钥(Google开发者控制台获取)',
  jwtSecret: '自定义JWT密钥,用于生成业务令牌'
};

2. 授权服务(src/services/googleAuthService.js)

const { OAuth2Client } = require('google-auth-library');
const config = require('../config/google');
const jwt = require('jsonwebtoken');

const client = new OAuth2Client(config.clientId);

// 验证Google ID Token合法性
async function verifyGoogleIdToken(idToken) {
  const ticket = await client.verifyIdToken({
    idToken: idToken,
    audience: config.clientId, // 确保Token是颁发给当前应用的
  });
  return ticket.getPayload(); // 返回用户信息:sub(Google唯一ID)、email、name等
}

// 生成后端业务JWT
function generateJwt(userData) {
  return jwt.sign(
    { userId: userData.sub, email: userData.email },
    config.jwtSecret,
    { expiresIn: '7d' } // 设置令牌有效期
  );
}

module.exports = { verifyGoogleIdToken, generateJwt };

3. 登录路由(src/routes/auth.js)

const express = require('express');
const router = express.Router();
const { verifyGoogleIdToken, generateJwt } = require('../services/googleAuthService');

router.post('/google', async (req, res) => {
  try {
    const { idToken } = req.body;
    if (!idToken) {
      return res.status(400).json({ message: '缺少ID Token' });
    }

    // 验证Google Token
    const userPayload = await verifyGoogleIdToken(idToken);

    // 此处可根据userPayload.sub查询本地数据库,无则创建用户
    // 示例:假设已完成用户查询/创建逻辑
    const user = { id: userPayload.sub, email: userPayload.email, name: userPayload.name };

    // 生成后端业务令牌
    const token = generateJwt(userPayload);

    res.json({ token, user });
  } catch (err) {
    console.error('验证失败', err);
    res.status(401).json({ message: 'Google登录验证失败' });
  }
});

module.exports = router;

4. 服务启动文件(server.js)

const express = require('express');
const authRoutes = require('./src/routes/auth');
const cors = require('cors');

const app = express();
// 跨域支持,适配Expo客户端与后端的跨域请求
app.use(cors());
// 解析JSON请求体
app.use(express.json());

// 挂载登录路由
app.use('/api/auth', authRoutes);

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`服务器运行在端口 ${PORT}`);
});

四、关键注意事项

  • 禁止客户端直接使用用户信息做业务判断:客户端数据可被篡改,必须经过后端验证后再处理
  • Google客户端密钥需保密:仅存放在后端,绝对不能暴露在前端代码中
  • JWT鉴权:后续客户端访问API时,需在请求头携带Authorization: Bearer <后端JWT令牌>,后端通过中间件验证令牌合法性
  • 生产环境强制HTTPS:防止Token在传输过程中被窃听

内容的提问来源于stack exchange,提问作者abankitbaid

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 16:25:24