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

NextJS 13中Next-Auth结合Strapi实现Google登录的用户持久化与令牌获取问题

NextJS 13 + NextAuth + Strapi Google 认证解决方案

前置准备

先在 Strapi 端完成 Google 认证配置:

  • 启用 Strapi 的「Users & Permissions」插件
  • 在插件设置中开启 Google 认证,填入和 NextAuth 一致的 Google Client ID、Client Secret
  • Google 控制台添加 NextAuth 回调地址:http://localhost:3000/api/auth/callback/google(生产环境替换为你的域名)

修正后的 NextAuth 配置代码

app/api/auth/[...nextauth]/route.ts

import NextAuth from 'next-auth';
import GoogleProvider from "next-auth/providers/google";
import type { NextAuthOptions, Session, JWT } from 'next-auth';

const authOptions: NextAuthOptions = {
    providers: [
        GoogleProvider({
            clientId: process.env.GOOGLE_CLIENT_ID as string,
            clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
            authorization: {
                params: {
                    scope: 'openid email profile'
                }
            }
        })
    ],
    callbacks: {
        async jwt({ token, user, account }): Promise<JWT> {
            if (user && account) {
                try {
                    // 调用 Strapi 的 Google OAuth 回调,交换 Strapi JWT
                    const strapiResponse = await fetch(
                        `${process.env.NEXT_PUBLIC_API_URL}/api/auth/google/callback`,
                        {
                            method: 'POST',
                            headers: { 'Content-Type': 'application/json' },
                            body: JSON.stringify({ access_token: account.accessToken })
                        }
                    );

                    if (!strapiResponse.ok) throw new Error('Strapi 认证失败');

                    const strapiData = await strapiResponse.json();
                    // 存入 Strapi 令牌和用户 ID 到 NextAuth Token
                    token.strapiJwt = strapiData.jwt;
                    token.strapiUserId = strapiData.user.id;
                    token.email = user.email;
                    token.name = user.name;
                    token.picture = user.image;
                } catch (err) {
                    console.error('Strapi OAuth 回调错误:', err);
                    throw err;
                }
            }
            return token;
        },
        
        async session({ session, token }): Promise<Session> {
            if (session.user) {
                // 把 Strapi 令牌同步到前端 Session
                session.user.strapiJwt = token.strapiJwt as string;
                session.user.strapiUserId = token.strapiUserId as string;
                session.user.email = token.email as string;
                session.user.name = token.name as string;
                session.user.image = token.picture as string;
            }
            return session;
        },
    },
    secret: process.env.NEXTAUTH_SECRET as string,
    pages: { signIn: '/auth/signin' }
};

const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };

核心问题解答

1. 如何将用户信息持久化到 Strapi 数据库?

通过调用 Strapi 官方提供的 /api/auth/google/callback 端点,Strapi 的「Users & Permissions」插件会自动处理:

  • 如果 Google 账号对应的邮箱已在 Strapi 存在,直接关联该账号
  • 如果不存在,自动创建新用户并同步 Google 返回的邮箱、姓名、头像等信息
    无需手动编写数据库操作代码,插件已封装好完整逻辑。

2. 如何获取 Strapi 访问令牌并用于 API 请求?

  • 在 jwt 回调中提取 Strapi 返回的 jwt 字段,存入 NextAuth 的 Token 中
  • 通过 session 回调将令牌同步到前端可用的 Session 对象
  • 后续请求 Strapi 受保护 API 时,在请求头中携带令牌:
    import { getServerSession } from 'next-auth/next';
    import authOptions from './api/auth/[...nextauth]/route';
    
    async function fetchProtectedStrapiData() {
        const session = await getServerSession(authOptions);
        if (!session?.user?.strapiJwt) throw new Error('用户未认证');
    
        const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/protected-endpoint`, {
            headers: { 'Authorization': `Bearer ${session.user.strapiJwt}` }
        });
    
        return response.json();
    }
    

额外配置(TypeScript 类型扩展)

在项目根目录创建 types/next-auth.d.ts,扩展 Session 和 JWT 类型:

import type { DefaultSession, DefaultJWT } from 'next-auth';

declare module 'next-auth' {
    interface Session extends DefaultSession {
        user: DefaultSession['user'] & {
            strapiJwt: string;
            strapiUserId: string;
        };
    }

    interface JWT extends DefaultJWT {
        strapiJwt: string;
        strapiUserId: string;
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 04:35:34