通过nextauth 完成github登录认证,并将登录数据存入supabase数据库

糖哥l

使用AI开发WEB网站,必须使用一套AI友好的技术架构,使用NextJS及其相关生态技术栈成为很多人的选择,我近期正在使用开发一个网站

🏗️ 整体架构原理

认证流程图

用户点击登录 → GitHub OAuth → NextAuth.js 处理 → SupabaseAdapter → 数据存储到 Supabase
     ↓              ↓              ↓                ↓                    ↓
  前端页面      GitHub授权页    NextAuth回调处理    数据库适配器        PostgreSQL数据库

核心组件

  1. NextAuth.js: 认证框架,处理 OAuth 流程
  2. GitHub OAuth App: 提供第三方登录服务
  3. SupabaseAdapter: 将认证数据存储到 Supabase
  4. Supabase PostgreSQL: 云数据库存储用户信息

🔧 关键配置步骤

1. Supabase 数据库准备

首先在 Supabase 中创建相关表:

-- 创建
CREATE SCHEMA IF NOT EXISTS next_auth;

-- 创建用户表
CREATE TABLE IF NOT EXISTS next_auth.users (
  id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
  name text,
  email text UNIQUE,
  "emailVerified" timestamptz,
  image text
);

-- 创建账户关联表
CREATE TABLE IF NOT EXISTS next_auth.accounts (
  id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
  "userId" uuid NOT NULL REFERENCES next_auth.users(id) ON DELETE CASCADE,
  type text NOT NULL,
  provider text NOT NULL,
  "providerAccountId" text NOT NULL,
  refresh_token text,
  access_token text,
  expires_at bigint,
  token_type text,
  scope text,
  id_token text,
  session_state text,
  UNIQUE(provider, "providerAccountId")
);

-- 创建会话表
CREATE TABLE IF NOT EXISTS next_auth.sessions (
  id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
  "sessionToken" text NOT NULL UNIQUE,
  "userId" uuid NOT NULL REFERENCES next_auth.users(id) ON DELETE CASCADE,
  expires timestamptz NOT NULL
);

-- 创建验证令牌表
CREATE TABLE IF NOT EXISTS next_auth.verification_tokens (
  identifier text,
  token text UNIQUE,
  expires timestamptz NOT NULL,
  PRIMARY KEY (identifier, token)
);

2. 环境变量配置

# NextAuth.js 配置
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=your-secret-key

# Supabase 配置
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key

# GitHub OAuth 配置
AUTH_GITHUB_ID=your-github-client-id
AUTH_GITHUB_SECRET=your-github-client-secret
NEXT_PUBLIC_AUTH_GITHUB_ENABLED=true

💻 核心代码实现

1. NextAuth.js 配置 (auth/config.ts)

import GitHubProvider from "next-auth/providers/github";
import { AuthOptions } from "next-auth";
import { SupabaseAdapter } from "@auth/supabase-adapter";

export const authOptions: AuthOptions = {
  // 🔑 关键:使用 SupabaseAdapter 连接数据库
  adapter: SupabaseAdapter({
    url: process.env.NEXT_PUBLIC_SUPABASE_URL!,
    secret: process.env.SUPABASE_SERVICE_ROLE_KEY!,
  }),
  
  // 🔐 配置 GitHub OAuth 提供商
  providers: [
    GitHubProvider({
      clientId: process.env.AUTH_GITHUB_ID!,
      clientSecret: process.env.AUTH_GITHUB_SECRET!,
    })
  ],
  
  // 🛡️ 安全密钥
  secret: process.env.NEXTAUTH_SECRET,
  
  // 📄 自定义页面路径
  pages: {
    signIn: "/auth/signin",
    error: "/auth/error",
  },
  
  // 🔄 回调函数配置
  callbacks: {
    async signIn({ user, account, profile }) {
      // 登录验证逻辑
      return true;
    },
    
    async redirect({ url, baseUrl }) {
      // 登录后重定向逻辑
      if (url.startsWith("/")) return `${baseUrl}${url}`;
      return baseUrl;
    },
    
    async session({ session, token }) {
      // 会话数据处理
      if (session?.user && token) {
        session.user.id = token.uid as string;
      }
      return session;
    },
    
    async jwt({ token, user }) {
      // JWT 令牌处理
      if (user) {
        token.uid = user.id;
      }
      return token;
    },
  },
  
  // 📊 会话策略
  session: {
    strategy: "jwt",
  },
  
  // 🐛 开发环境调试
  debug: process.env.NODE_ENV === 'development',
};

2. NextAuth.js 初始化 (auth/index.ts)

import NextAuth from "next-auth";
import { authOptions } from "./config";

const nextAuth = NextAuth(authOptions);

export default nextAuth;
export const { auth, signIn, signOut } = nextAuth;

3. API 路由配置 (app/api/auth/[...nextauth]/route.ts)

import NextAuth from "next-auth";
import { authOptions } from "@/auth/config";

const handler = NextAuth(authOptions);

// 🚀 导出 GET 和 POST 处理器
export { handler as GET, handler as POST };

🔄 完整数据流程解析

第一步:用户点击登录

// 前端触发登录
import { signIn } from "next-auth/react";

<button onClick={() => signIn('github')}>
  Continue with GitHub
</button>

第二步:GitHub OAuth 授权

  1. 用户被重定向到 GitHub 授权页面
  2. GitHub 返回授权码到回调 URL
  3. NextAuth.js 接收授权码

第三步:NextAuth.js 处理认证

从日志可以看到详细过程:

# 1. 创建授权 URL
[next-auth][debug][GET_AUTHORIZATION_URL] {
  url: 'https://github.com/login/oauth/authorize?client_id=...'
}

# 2. 获取用户信息
[next-auth][debug][PROFILE_DATA] {
  OAuthProfile: {
    login: 'bytevirts',
    email: 'bytevirt@gmail.com',
    // ... 其他用户信息
  }
}

# 3. 检查用户是否存在
[next-auth][debug][adapter_getUserByEmail] { args: [ 'XXX@gmail.com' ] }

# 4. 创建新用户(如果不存在)
[next-auth][debug][adapter_createUser] {
  args: [{
    name: 'XXX',
    email: 'XXX@gmail.com',
    image: 'https://avatars.githubusercontent.com/u/XXX?v=4'
  }]
}

# 5. 关联 GitHub 账户
[next-auth][debug][adapter_linkAccount] {
  args: [{
    provider: 'github',
    providerAccountId: '204438200',
    userId: 'XXX-c325-4968-9b46-7a85ed96982b'
  }]
}

第四步:SupabaseAdapter 存储数据

SupabaseAdapter 自动执行以下操作:

  1. 检查用户是否存在:查询 users
  2. 创建用户记录:插入新用户到 users
  3. 关联账户信息:插入 GitHub 账户信息到 accounts
  4. 生成会话:创建用户会话记录

第五步:登录成功

NextAuth signIn event: {
  user: {
    id: '1481a099-c325-4968-9b46-7a85ed96982b',
    name: 'xxx',
    email: 'xxx@gmail.com'
  },
  isNewUser: true
}

📊 Supabase 数据库结构

登录成功后,Supabase 中的数据结构:

users

id: 1481a099-c325-4968-9b46-7a85ed96982b
name: bytevirts
email: XXX@gmail.com
image: https://avatars.githubusercontent.com/u/204438200?v=4
emailVerified: null

accounts

userId: 1481a099-c325-4968-9b46-7a85ed96982b
provider: github
providerAccountId: 204438200
access_token: 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
token_type: bearer
scope: read:user,user:email

🛠️ 遇到的问题和解决方案

1. Schema 权限问题

问题:nextjs操作supabase时提示没有权限

解决方案:在 Supabase Dashboard 中将schema如 next_auth 添加到 Exposed schemas

🎯 核心优势

  1. 安全性:OAuth 2.0 标准,无需存储密码
  2. 可扩展性:支持多种登录方式(GitHub、Google 等)
  3. 数据持久化:用户信息安全存储在 Supabase 云数据库
  4. 开发友好:NextAuth.js 提供完整的认证解决方案
  5. 类型安全:TypeScript 支持,减少运行时错误

这个完整的认证系统现在已经可以:

  • ✅ 安全地处理 GitHub OAuth 登录
  • ✅ 自动创建和管理用户账户
  • ✅ 将所有数据持久化存储到 Supabase
  • ✅ 提供完整的会话管理功能

跟着操作一遍,就能基本理解登录的流程!

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部