Next.js使用Supabase实现Github登录

这篇具有很好参考价值的文章主要介绍了Next.js使用Supabase实现Github登录。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Next.js 有许多 OAuth 认证方案来实现 Github 或者 Google 登录,比较常见的有 next-auth、clerk、supabase等。Supabase提供了很多的核心服务,包括 PostgreSQL 数据库、身份验证、文件存储等。

本文将介绍如何使用 Supabase 实现 Github 登录,您将学到:

  1. 使用 OAuth 认证登录。
  2. 使用 Github 注册自动创建用户表数据。
  3. 用户数据缓存(zustand)。
  4. 路由守卫。

在继续开始前,您需要具备以下的基本知识:

  • Node.js
  • npm/pnpm
  • Next.js

起步

项目初始化

使用 pnpm 创建最新的 Next.js 项目。

Node.js 版本至少需要 v18.17。

PS J:\next-project> pnpm create create-next-app@latest
√ What is your project named? ... next-auth
√ Would you like to use TypeScript? ... No / Yes
√ Would you like to use ESLint? ... No / Yes
√ Would you like to use Tailwind CSS? ... No / Yes
√ Would you like to use `src/` directory? ... No / Yes
√ Would you like to use App Router? (recommended) ... No / Yes
√ Would you like to customize the default import alias (@/*)? ... No / Yes

dependencies:
+ next 14.0.3
+ react 18.2.0
+ react-dom 18.2.0

devDependencies:
+ @types/node 20.10.3
+ @types/react 18.2.41
+ @types/react-dom 18.2.17
+ autoprefixer 10.4.16
+ eslint 8.55.0
+ eslint-config-next 14.0.3
+ postcss 8.4.32
+ tailwindcss 3.3.5
+ typescript 5.3.2

Next.js使用Supabase实现Github登录,Next.js,javascript,react.js,前端,typescript

在终端启动项目:

pnpm run dev

浏览器打开 http://localhost:3000/ 将看到:

Next.js使用Supabase实现Github登录,Next.js,javascript,react.js,前端,typescript

创建 Supabase 项目

  1. 首先进入 supabase 创建一个账户。
  2. 登录成功后进入 dashboard ,点击 New project。
  3. 设置项目名、数据库密码以及所属地区。

开始

为了实现一个好看的页面,我这里将使用 shadcn-ui 来作为项目的 ui 组件库。

安装 shadcn-ui:

PS J:\next-project\next-auth> pnpm dlx shadcn-ui@latest init
√ Would you like to use TypeScript (recommended)? ... no / yes
√ Which style would you like to use? » New York
√ Which color would you like to use as base color? » Zinc
√ Where is your global CSS file? ... app/globals.css
√ Would you like to use CSS variables for colors? ... no / yes
√ Where is your tailwind.config.js located? ... tailwind.config.ts
√ Configure the import alias for components: ... @/components
√ Configure the import alias for utils: ... @/lib/utils
√ Are you using React Server Components? ... no / yes
√ Write configuration to components.json. Proceed? ... yes

Next.js使用Supabase实现Github登录,Next.js,javascript,react.js,前端,typescript

添加 Button 按钮:

pnpm dlx shadcn-ui@latest add button

添加 Lucide 图标库:

pnpm install lucide-react

修改 app/page.tsx

import { Button } from "@/components/ui/button";
import { Github } from "lucide-react";

export default function Home() {
  return (
    <div>
      <Button className="flex items-center gap-1">
        <Github size={18} />
        Login
      </Button>
    </div>
  );
}

在 Next.js 中使用 Supabase

安装 Supabase 包

pnpm install @supabase/ssr @supabase/supabase-js

在项目根目录新建一个 .env.local 文件,SUPABASE_URL 和 SUPABASE_ANON_KEY 可以在 https://supabase.com/dashboard/project/_/settings/api 中获取。

NEXT_PUBLIC_SUPABASE_URL=your_supabase_project_url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key

Next.js使用Supabase实现Github登录,Next.js,javascript,react.js,前端,typescript

在根目录新建 middleware.ts 文件。输入以下内容:

import { createServerClient, type CookieOptions } from '@supabase/ssr'
import { NextResponse, type NextRequest } from 'next/server'

export async function middleware(request: NextRequest) {
  let response = NextResponse.next({
    request: {
      headers: request.headers,
    },
  })

  const supabase = createServerClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    {
      cookies: {
        get(name: string) {
          return request.cookies.get(name)?.value
        },
        set(name: string, value: string, options: CookieOptions) {
          request.cookies.set({
            name,
            value,
            ...options,
          })
          response = NextResponse.next({
            request: {
              headers: request.headers,
            },
          })
        },
        remove(name: string, options: CookieOptions) {
          request.cookies.set({
            name,
            value: '',
            ...options,
          })
          response = NextResponse.next({
            request: {
              headers: request.headers,
            },
          })
        },
      },
    }
  )

  await supabase.auth.getSession()

  return response
}

新建 /app/auth/callback/route.ts 文件:

import { cookies } from "next/headers";
import { NextResponse } from "next/server";
import { type CookieOptions, createServerClient } from "@supabase/ssr";

export async function GET(request: Request) {
  const { searchParams, origin } = new URL(request.url);
  const code = searchParams.get("code");
  // if "next" is in param, use it as the redirect URL
  const next = searchParams.get("next") ?? "/";

  if (code) {
    const cookieStore = cookies();
    const supabase = createServerClient(
      process.env.NEXT_PUBLIC_SUPABASE_URL!,
      process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
      {
        cookies: {
          get(name: string) {
            return cookieStore.get(name)?.value;
          },
          set(name: string, value: string, options: CookieOptions) {
            cookieStore.set({ name, value, ...options });
          },
          remove(name: string, options: CookieOptions) {
            cookieStore.delete({ name, ...options });
          },
        },
      }
    );
    const { error } = await supabase.auth.exchangeCodeForSession(code);
    if (!error) {
      return NextResponse.redirect(`${origin}${next}`);
    }
  }

  // return the user to an error page with instructions
  return NextResponse.redirect(`${origin}/auth/auth-code-error`);
}

添加 Supabase 的 Auth Provider.

  1. 访问 https://supabase.com/dashboard/project/_/auth/providers,找到 Github,开启。
  2. 访问 https://github.com/settings/developers,点击 New Oauth App,Homepage URL 填入 http://localhost:3000/ , Authorization callback URL 填入 Supabase 提供的 Callback URL (for OAuth),点击 Register Application。
  3. 点击 Generate a new client secret,复制秘钥。
  4. 将 Client ID 和 Client Secret 分别填入,点击 Save。

Next.js使用Supabase实现Github登录,Next.js,javascript,react.js,前端,typescript

Next.js使用Supabase实现Github登录,Next.js,javascript,react.js,前端,typescript

Next.js使用Supabase实现Github登录,Next.js,javascript,react.js,前端,typescript

修改 app/page.tsx

"use client";

import { createBrowserClient } from "@supabase/ssr";
import { Github } from "lucide-react";

import { Button } from "@/components/ui/button";

export default function Home() {
	const pathname = usePathname;

  const supabase = createBrowserClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
  );

  const handleLogin = async () => {
    await supabase.auth.signInWithOAuth({
      provider: "github",
      options: {
        redirectTo: location.origin + "/auth/callback?next=" + pathname,
      },
    });
  };

  const handleLogout = async () => {
    await supabase.auth.signOut();
  };

  return (
    <div className="flex gap-2">
      <Button onClick={handleLogin} className="flex items-center gap-1">
        <Github size={18} />
        Login
      </Button>
      <Button onClick={handleLogout} className="flex items-center gap-1">
			  <LogOut size={18} />
				Logout
			</Button>
    </div>
  );
}

点击登录按钮,认证成功将返回首页 http://localhost:3000,此时我们已经完成了最基础的登录登出功能。

Next.js使用Supabase实现Github登录,Next.js,javascript,react.js,前端,typescript

用户信息缓存

安装 zustand

pnpm install zustand

创建文件 /lib/store/user.ts

import { create } from "zustand";
import { User } from "@supabase/supabase-js";

interface UserState {
  user: User | undefined;
  setUser: (user: User | undefined) => void;
}

export const useUser = create<UserState>((set) => ({
  user: undefined,
  setUser: (user) => set(() => ({ user })),
}));

创建文件 /components/session-provider.tsx

"use client";

import { useUser } from "@/lib/store/user";
import { createBrowserClient } from "@supabase/ssr";
import { useCallback, useEffect } from "react";

const SessionProvider = () => {
  const setUser = useUser((state) => state.setUser);

  const supabase = createBrowserClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
  );

  const userSession = useCallback(async () => {
    const { data } = await supabase.auth.getSession();
    setUser(data.session?.user);
  }, [setUser, supabase]);

  useEffect(() => {
    userSession();
  }, [userSession]);

  return null
};

export default SessionProvider;

/app/layout.tsx 中引入 session-provider。

import SessionProvider from "@/components/session-provider";
...
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body className={inter.className}>
        {children}
        <SessionProvider />
      </body>
    </html>
  );
}

修改 /app/page.tsx

"use client";

import { createBrowserClient } from "@supabase/ssr";
import { Github, LogOut } from "lucide-react";

import { Button } from "@/components/ui/button";
import { useUser } from "@/lib/store/user";

export default function Home() {
	const pathname = usePathname;

  const user = useUser((state) => state.user);
  const setUser = useUser((state) => state.setUser);

  console.log(user, "user");

  const supabase = createBrowserClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
  );

  const handleLogin = async () => {
    await supabase.auth.signInWithOAuth({
      provider: "github",
      options: {
        redirectTo: location.origin + "/auth/callback?next=" + pathname,
      },
    });
  };

  const handleLogout = async () => {
    await supabase.auth.signOut();
    setUser(undefined);
  };

  return (
    <div>
      <h1 className="text-2xl py-2">Hi: {user?.user_metadata?.user_name}</h1>
      <div className="flex gap-2">
        {!user?.id ? (
          <Button onClick={handleLogin} className="flex items-center gap-1">
            <Github size={18} />
            Login
          </Button>
        ) : (
          <Button onClick={handleLogout} className="flex items-center gap-1">
            <LogOut size={18} />
            Logout
          </Button>
        )}
      </div>
    </div>
  );
}

同步数据表

访问 https://supabase.com/dashboard/project/_/database/tables,点击 New table,创建一张 users 数据表。

Next.js使用Supabase实现Github登录,Next.js,javascript,react.js,前端,typescript

创建完成后进入 SQL Editor 填入下面两个 SQL,执行。

-- 创建 create_user_on_signup 函数,1.在 public.users 表中插入一条新的记录。2.更新 auth.users 表中的 raw_user_meta_data 字段。
CREATE FUNCTION create_user_on_signup() RETURNS TRIGGER AS $$
BEGIN
    INSERT INTO public.users (id, email, user_name, image_url) VALUES (
      NEW.id,
      NEW.raw_user_meta_data ->> 'email',
      NEW.raw_user_meta_data ->> 'user_name',
      NEW.raw_user_meta_data ->> 'avatar_url'
    );
    UPDATE auth.users SET raw_user_meta_data = raw_user_meta_data || '{"role": "user"}'::jsonb WHERE auth.users.id = NEW.id;
    RETURN NEW;
END;
$$ language plpgsql security definer;

-- 创建触发器,当 auth.users 表新增用户后自动触发 create_user_on_signup 函数
CREATE TRIGGER create_user_on_signup after INSERT ON auth.users FOR EACH ROW EXECUTE FUNCTION create_user_on_signup();
  1. 进入 Authentication 将已经授权的用户删除
  2. 重新点击登录。此时 users 表已经同步新增了一条数据。

路由守卫

我们的一些页面是不希望未登录用户或者普通用户进行访问的,于是需要对页面进行拦截。

修改 middleware.ts 文件:

export async function middleware(request: NextRequest) {
	...
	const { data } = await supabase.auth.getSession();

  if (!data.session || data.session.user.user_metadata.role !== 'admin') {
    return NextResponse.redirect(new URL('/', request.url));
  }

  return response;
}

export const config = {
  matcher: ["/admin/:path*"],
};

新建 /app/admin/page.ts

const AdminPage = () => {
  return <div>admin page</div>;
};

export default AdminPage;

此时访问 http://localhost:3000/admin 会被重定向到首页。

进入 SQL Editor 修改我们的权限:

UPDATE users SET role = 'admin' WHERE id = '254ec4d1-a5bb-46de-9a29-134aa59ddfcb';

UPDATE auth.users SET raw_user_meta_data = raw_user_meta_data || '{"role": "admin"}'::jsonb WHERE auth.users.id = '254ec4d1-a5bb-46de-9a29-134aa59ddfcb';

id 可以在 user 表或者 Authentication 页面中复制。

退出重新登录,再次访问 /admin 页面,成功进入。文章来源地址https://www.toymoban.com/news/detail-753444.html

到了这里,关于Next.js使用Supabase实现Github登录的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 使用 Flask 部署 Next.js

    原文 使用 Flask 部署 Next.js Flask 和 Next.js 是两个独特的开源 Web 框架,分别构建在 Python 和 JavaScript 编程语言之上。 您可以在没有 Next.js 的情况下构建 Flask 应用程序,也可以在没有 Flask 的情况下构建 Next.js 应用程序。但是,您可能会发现自己使用 Flask 构建了一个应用程序,

    2024年02月12日
    浏览(48)
  • 使用 Next.js 连接 mysql 数据库

    本文主要为大家介绍,如何使用 Next 框架实现一个简单的 后端接口 ,并且从 数据库 中请求数据返回给前端。 项目创建完成后在 app 文件下新建api文件夹,在 api 文件夹下新建 getData 文件夹,在 getData 文件夹下新建 route.js,这里面用于存储我们的接口信息,如下 注意: 在

    2024年02月22日
    浏览(64)
  • Elasticsearch快速入门及结合Next.js案例使用

    🎉欢迎来到Java学习路线专栏~Elasticsearch快速入门及结合Next.js案例使用 ☆* o(≧▽≦)o *☆嗨~我是IT·陈寒🍹 ✨博客主页:IT·陈寒的博客 🎈该系列文章专栏:Java学习路线 📜其他专栏:Java学习路线 Java面试技巧 Java实战项目 AIGC人工智能 数据结构学习 🍹文章作者技术和水平有

    2024年02月03日
    浏览(37)
  • React18.x + i18next + antd 国际化正确使用姿势及避坑指南

    如果你使用这个教程还不能够解决你的问题的话,直接私信我,免费一对一给你解决。 具体的创建方法大家参考vite官方文档,大概的操作如下,如果需要更详细的,大家去自行搜索即可 因为我这里使用的是ts版本,所以,你自己看着办吧。 其中 i18next-browser-languagedetector i1

    2024年02月05日
    浏览(62)
  • JavaScript框架 Angular、React、Vue.js 的全栈解决方案比较

    在 Web 开发领域,JavaScript 提供大量技术栈可供选择。其中最典型的三套组合,分别是 MERN、MEAN 和 MEVN。前端框架(React、Angular 和 Vue)进行简化比较。 MERN 技术栈包含四大具体组件: MongoDB:一款强大的 NoSQL 数据库,以灵活的 JSON 格式存储数据。 Express.js:一套极简但强大的

    2024年02月03日
    浏览(58)
  • 2023年最佳JavaScript框架:React、Vue、Angular和Node.js的比较

    🎉欢迎来到Java学习路线专栏~探索2023年最佳JavaScript框架:React、Vue、Angular和Node.js的比较 ☆* o(≧▽≦)o *☆嗨~我是IT·陈寒🍹 ✨博客主页:IT·陈寒的博客 🎈该系列文章专栏:Java学习路线 📜其他专栏:Java学习路线 Java面试技巧 Java实战项目 AIGC人工智能 🍹文章作者技术和水

    2024年02月11日
    浏览(49)
  • next.js app目录 i18n国际化简单实现

    最近在用next写一个多语言的项目,找了好久没找到简单实现的教程,实践起来感觉都比较复杂,最后终于是在官方文档找到了,结合网上找到的代码demo,终于实现了,在这里简单总结一下。 此教程适用于比较简单的项目实现,如果你是刚入门next,并且不想用太复杂的方式去

    2024年04月22日
    浏览(43)
  • Node.js npm V8 React Express的运行配合关系:构建JavaScript应用的基石

    目录 Node.js 和 V8 引擎 Node.js 和 npm LTS(Long Term Support) React Node.js的作用 Express Node.js 和 V8 引擎 Node.js 使用 Google 的 V8 JavaScript 引擎 来执行 JavaScript 代码。V8 是一个高性能的 JavaScript 和 WebAssembly 引擎,用于在 Google Chrome 浏览器和 Node.js 中运行 JavaScript。 V8 引擎的更新 通常包括

    2024年03月12日
    浏览(64)
  • 在服务器部署Next.js、Node.js项目,并实现自动部署(伪CI\CD)超详细

    目录 一、引言 二、配置服务器 1. 远程连接服务器 · 用服务商提供的远程连接 · 用MotaXterm来远程连接 ​编辑​编辑​编辑  2. 登录实例 · 如何获取账号和密码 · 服务商远程连接方式:  · MotaXterm连接方式 三、项目准备与测试 1. 安装nodejs · 进入安装目录 · 下载 · 解压 ·

    2024年02月05日
    浏览(96)
  • 使用Python突破某网游游戏JS加密限制,进行逆向解密,实现自动登录

    兄弟们天天看基础看腻了吧 今天来分享一下如何使用Python突破某网游游戏JS加密限制,进行逆向解密,实现自动登录。 目标:某 7 网游登录 主页:aHR0cHM6Ly93d3cuMzcuY29tLw== 接口:aHR0cHM6Ly9teS4zNy5jb20vYXBpL2xvZ2luLnBocA== 逆向参数:Query String Parameters: password: SlVEOThrcjgzNDNjaUYxOTQzNDM0eVM

    2023年04月13日
    浏览(65)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包