Next.js+NextAuth.js接入Google Oauth登录

74次阅读
没有评论

最近在项目中集成 Google OAuth 登录功能,从配置到部署遇到了不少坑。整理成文,希望能帮到同样在路上的开发者们。

🎯 项目背景

使用技术栈:Next.js 13 + NextAuth.js + Vercel 部署

需求:为 Web 应用添加 Google 一键登录功能,用户登录后自动创建账户并赠送积分。

📋 完整配置流程

第一步:Google Cloud Console 详细配置

这是整个流程的第一步,也是最容易出错的地方。很多开发者都是在这里踩坑的!

1. 创建 Google Cloud 项目

Step 1: 访问 Google Cloud Console

  • 打开 Google Cloud Console
  • 使用你的 Google 账号登录

Step 2: 创建新项目

  • 点击顶部项目选择器
  • 点击「新建项目」按钮
  • 填写项目名称(如:my-nextjs-app)
  • 选择组织(个人开发者可选择「无组织」)
  • 点击「创建」

💡 小技巧:项目名称建议使用英文,避免后续配置时出现编码问题。

Next.js+NextAuth.js 接入 Google Oauth 登录

2. 启用 Google+ API(重要!)

很多人会忽略这一步,导致后面认证失败:

Next.js+NextAuth.js 接入 Google Oauth 登录

Step 1: 进入 API 库

  • 在左侧菜单中找到「API 和服务」→「库」
  • 或者直接搜索「Google+ API」

Step 2: 启用必要的 API

需要启用的 API:
✅ Google+ API (已废弃,但某些功能仍需要)
✅ People API (推荐使用,获取用户信息)
✅ Gmail API (如果需要访问邮箱信息)

Step 3: 启用操作

  • 点击每个 API 卡片
  • 点击「启用」按钮
  • 等待启用完成(通常几秒钟)

⚠️ 注意:如果不启用这些 API,后面会出现「access_denied」错误!

3. 配置 OAuth 同意屏幕(关键步骤)

这一步决定了用户看到的登录授权页面:

Next.js+NextAuth.js 接入 Google Oauth 登录

Step 1: 进入 OAuth 同意屏幕设置

  • 左侧菜单:「API 和服务」→「OAuth 同意屏幕」

Step 2: 选择用户类型

🔸 内部:仅限组织内用户(需要 Google Workspace)
🔸 外部:任何 Google 用户都可以使用(推荐)

对于个人开发者或对外开放的应用,选择「外部」。

Step 3: 填写应用信息

基本信息设置:

应用名称:用户在授权页面看到的名称 
用户支持电子邮件:你的邮箱地址  
应用徽标:可选,建议上传 120x120 像素的 PNG
应用首页:你的应用主页 URL
应用隐私权政策:隐私政策页面链接
应用服务条款:服务条款页面链接(可选)

授权网域(重要):

开发环境:localhost
生产环境:yourdomain.com(不带 https://)
测试环境:test.yourdomain.com

💡 填写示例

应用名称:我的 Web 应用 
用户支持电子邮件:[email protected]
应用首页:https://yourdomain.com
授权网域:
  - localhost
  - yourdomain.com

Step 4: 配置作用域

对于基本的 Google 登录,添加以下作用域:

✅ ../auth/userinfo.email    - 获取用户邮箱
✅ ../auth/userinfo.profile  - 获取用户基本信息  
✅ openid                   - OpenID 标识符

Step 5: 测试用户(可选)

如果应用处于测试状态,需要添加测试用户的邮箱地址:

测试用户:
- [email protected]
- [email protected]

4. 创建 OAuth 2.0 客户端 ID(核心配置)

Step 1: 进入凭据页面

  • 左侧菜单:「API 和服务」→「凭据」
  • 点击「+ 创建凭据」→「OAuth 2.0 客户端 ID」

Step 2: 选择应用类型

  • 选择「Web 应用」

Step 3: 配置客户端信息

名称设置:

名称:NextJS App OAuth Client(建议使用描述性名称)

已获授权的 JavaScript 来源:

开发环境:
http://localhost:3000

生产环境:
https://yourdomain.com

已获授权的重定向 URI(最关键!):

开发环境:
http://localhost:3000/api/auth/callback/google

生产环境:
https://yourdomain.com/api/auth/callback/google

⚠️ 重点提醒:重定向 URI 格式必须严格按照 NextAuth.js 的规范:/api/auth/callback/[provider 名称]

Next.js+NextAuth.js 接入 Google Oauth 登录

Step 4: 保存配置

  • 点击「创建」
  • 系统会显示客户端 ID 和客户端密钥
  • 立即复制保存这两个值!
Next.js+NextAuth.js 接入 Google Oauth 登录

5. 获取配置信息

配置完成后,你会得到:

客户端 ID:12345678-abcdefg.apps.googleusercontent.com
客户端密钥:GOCSPX-abcdefghijklmnopqrstuvwxyz

🔥 Google Console 配置常见错误

错误 1: redirect_uri_mismatch

错误信息:

Error 400: redirect_uri_mismatch

原因:  重定向 URI 配置错误

解决方案:

✅ 正确格式:http://localhost:3000/api/auth/callback/google
❌ 错误格式:http://localhost:3000/api/auth/google/callback
❌ 错误格式:http://localhost:3000/auth/callback/google

错误 2: access_denied

错误信息:

Error: access_denied

原因:

  1. 未启用必要的 API
  2. OAuth 同意屏幕配置不完整
  3. 测试用户未添加(应用在测试状态下)

解决方案:

  1. 确保启用了 People API
  2. 完整填写 OAuth 同意屏幕信息
  3. 添加测试用户邮箱

错误 3: invalid_client

错误信息:

Error: invalid_client

原因:  客户端 ID 或密钥错误

解决方案:

  1. 检查环境变量中的 GOOGLE_CLIENT_ID
  2. 确保客户端密钥正确复制
  3. 检查是否有隐藏字符或空格

🔥 踩坑历程

第一坑:Server error – 服务器配置问题

现象:  点击 Google 登录后,页面显示“Server error – There is a problem with the server configuration”

原因分析:  环境变量配置不完整或错误

解决方案:

# .env.local 必须包含以下配置
NEXTAUTH_SECRET="your_generated_secret"
NEXTAUTH_URL="https://your-domain.com"
GOOGLE_CLIENT_ID="your_google_client_id"
GOOGLE_CLIENT_SECRET="your_google_client_secret"

重点提醒:

  • NEXTAUTH_SECRET  使用命令生成:openssl rand -base64 32
  • Vercel 部署后需要在环境变量中重新设置
  • 本地和生产环境的  NEXTAUTH_URL  要对应正确的域名

第二坑:This action with HTTP GET is not supported

现象: URL 跳转到  /api/auth/error,显示不支持 GET 请求

排查过程:

  1. 首先怀疑是文件路径问题
  2. 检查 NextAuth 配置文件位置
  3. 最终发现是回调地址配置错误

根本原因: Google OAuth 回调地址配置错误!

// ❌ 错误配置
GOOGLE_REDIRECT_URI="https://domain.com/api/auth/google/callback"

// ✅ 正确配置  
GOOGLE_REDIRECT_URI="https://domain.com/api/auth/callback/google"

关键发现: NextAuth.js 的回调地址格式是固定的:/api/auth/callback/[provider]

📋 NextAuth.js 代码配置

完整的 NextAuth.js 配置文件

App Router (Next.js 13+):文件位置:app/api/auth/[...nextauth]/route.ts

import { Provider } from"next-auth/providers/index";
importGoogleProviderfrom"next-auth/providers/google";
import { AuthOptions } from"next-auth";
importNextAuthfrom"next-auth";
import {genUniSeq, getIsoTimestr} from"@/backend/utils";
import {saveUser} from"@/backend/service/user";
import { User } from"@/backend/type/type";
import {createCreditUsage} from"@/backend/service/credit_usage";
import {getCreditUsageByUserId} from"@/backend/service/credit_usage";

/**
 * 初始化认证提供商数组
 * 用于存储所有可用的登录方式(Google、GitHub、Facebook 等)
 */
letproviders: Provider[] = [];

/**
 * 配置 Google OAuth 登录提供商
 * 从环境变量中读取 Google 应用的客户端配置
 */
providers.push(
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID || "", // Google 应用客户端 ID
clientSecret: process.env.GOOGLE_CLIENT_SECRET || "", // Google 应用客户端密钥
// 🚨 重要:不要手动设置 redirect_uri,NextAuth.js 会自动处理
  })
);

/**
 * NextAuth.js 配置选项
 * 包含认证流程中的各种回调函数和配置参数
 */
constauthOptions: AuthOptions = {
secret: process.env.NEXTAUTH_SECRET, // 用于加密 JWT token 的密钥
  providers, // 认证提供商列表
callbacks: {
/**
     * 登录验证回调函数
     * 在用户尝试登录时被调用,用于决定是否允许用户登录
     */
asyncsignIn({user, account, profile, email, credentials}) {
// 在这里可以添加登录限制逻辑
// 例如:检查用户是否在白名单中,是否被封禁等
const isAllowedToSignIn = true;
if (isAllowedToSignIn) {
returntrue;
      } else {
// 可以返回 false 拒绝登录,或返回 URL 重定向到错误页面
returnfalse;
      }
    },

/**
     * 重定向回调函数
     * 控制认证流程完成后的页面跳转
     */
asyncredirect({url, baseUrl}) {
// 登录成功后重定向到首页
// 可以根据用户角色或其他条件重定向到不同页面
return`${baseUrl}/`;
    },

/**
     * Session 回调函数
     * 每次获取 session 时被调用,用于自定义返回给客户端的 session 对象
     */
asyncsession({session, token, user}) {
// 将 JWT token 中的用户信息合并到 session 中
// 这样前端就可以通过 useSession() 获取到完整的用户信息
if (token && token.user) {
        session.user = token.user;
      }
return session;
    },

/**
     * JWT 回调函数
     * 在 JWT token 被创建或更新时调用
     * 这是处理用户注册和数据库操作的核心函数
     */
asyncjwt({token, user, account}) {
// 仅在首次登录时处理(user 和 account 参数只在首次登录时存在)
if (user && user.email && account) {
try {
// 创建数据库用户对象
constdbUser: User = {
uuid: genUniSeq(), // 生成唯一用户 ID
email: user.email, // Google 账户邮箱
nickname: user.name || "", // Google 账户用户名
avatar_url: user.image || "", // Google 账户头像 URL
signin_type: account.type, // 登录类型(oauth)
signin_provider: account.provider, // 登录提供商(google)
signin_openid: account.providerAccountId, // Google 用户唯一标识
created_at: getIsoTimestr(), // 创建时间(ISO 格式)
signin_ip: "", // 登录 IP 地址(暂时为空,可后续添加获取逻辑)
          };

// 保存用户信息到数据库
// 如果用户已存在,通常 saveUser 函数会处理更新逻辑
awaitsaveUser(dbUser);

// 检查用户是否已有积分记录
const creditUsage = awaitgetCreditUsageByUserId(dbUser.uuid);

// 如果是新用户,创建积分记录并赠送初始积分
if (!creditUsage) {
awaitcreateCreditUsage({
user_id: dbUser.uuid, // 用户 ID
user_subscriptions_id: -1, // 订阅 ID(- 1 表示无订阅)
is_subscription_active: false, // 订阅状态(未激活)
used_count: 0, // 已使用积分数量
period_remain_count: 20, // 剩余积分数量(新用户赠送 20 积分)
period_start: newDate(), // 积分周期开始时间
period_end: newDate( // 积分周期结束时间(1 个月后)
newDate().setMonth(newDate().getMonth() + 1)
              ),
created_at: newDate(), // 记录创建时间
            });
          }

// 将用户信息存储到 JWT token 中
// 这些信息会在后续的 session 回调中被使用
          token.user = {
uuid: dbUser.uuid,
nickname: dbUser.nickname,
email: dbUser.email,
avatar_url: dbUser.avatar_url,
created_at: dbUser.created_at,
          };
        } catch (error) {
console.error('JWT 回调处理用户数据时出错:', error);
// 即使数据库操作失败,也继续认证流程
// 避免影响用户登录体验
        }
      }

return token;
    },
  },
};

/**
 * 创建 NextAuth 处理程序
 * 使用上面定义的配置选项初始化 NextAuth
 */
const handler = NextAuth(authOptions);

/**
 * 导出处理程序
 * 在 App Router (Next.js 13+) 中,需要同时导出 GET 和 POST 方法
 * 用于处理 NextAuth.js 的各种 HTTP 请求
 */
export {handler asGET, handler asPOST };

环境变量完整版

# NextAuth 基础配置
NEXTAUTH_SECRET=your_openssl_generated_secret
NEXTAUTH_URL=https://your-domain.com

# Google OAuth 配置  
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secret

# 数据库配置(如果需要)
DATABASE_URL=your_database_connection_string

🐛 调试技巧分享

1. 分步验证法

# 第一步:验证 NextAuth 路由 
http://localhost:3000/api/auth/providers

# 第二步:测试登录页面
http://localhost:3000/api/auth/signin  

# 第三步:检查回调处理
观察登录流程中的 URL 跳转

2. 日志调试

// 在 JWT callback 中添加日志
asyncjwt({token, user, account}) {
console.log('JWT Callback:', { user, account})
// 业务逻辑...
return token
}

3. Vercel 日志查看

部署后在 Vercel Dashboard > Functions 中查看详细错误信息

✅ 最佳实践总结

配置篇

  1. 环境变量命名要准确:NextAuth 对环境变量名称非常敏感
  2. 回调地址格式固定:遵循  /api/auth/callback/[provider]  格式
  3. 本地和生产分离:不同环境使用对应的域名和配置

开发篇

  1. 先本地调试:确保本地环境完全正常再部署
  2. 分层排查:从 Google Console → 环境变量 → 代码配置逐层检查
  3. 保留日志:在关键回调函数中保留日志便于排查

部署篇

  1. 重新设置环境变量:Vercel 部署后必须重新配置所有环境变量
  2. 域名要匹配:确保 NEXTAUTH_URL 与实际部署域名一致
  3. 重新部署:修改环境变量后需要触发重新部署

💡 写在最后

Google OAuth 集成看似简单,实际上细节很多。最容易出错的地方往往是:

  • Google Cloud Console 配置不完整
  • 环境变量拼写错误
  • 回调地址格式不对
  • 本地开发和生产环境配置混淆

建议开发时多用浏览器开发者工具查看网络请求,错误信息往往就隐藏在 HTTP 响应中。

遇到问题不要慌,按照配置清单逐项检查,99% 的问题都能解决。


如果这篇文章对你有帮助,记得点个在看!

有问题欢迎评论区讨论,我会尽力回复。让我们一起在开发路上少踩坑、多成长!

正文完
 0
Pa2sw0rd
版权声明:本站原创文章,由 Pa2sw0rd 于2025-09-21发表,共计7518字。
转载说明:Unless otherwise specified, all articles are published by cc-4.0 protocol. Please indicate the source of reprint.
评论(没有评论)