【Next.js 入门教程系列】07-身份验证

原文链接

CSDN 的排版/样式可能有问题,去我的博客查看原文系列吧,觉得有用的话, 给我的库点个star,关注一下吧

上一篇【Next.js 入门教程系列】06-上传文件

身份验证

本篇包括以下内容:

  • Setting up Next Auth
  • Configuring the Google Provider
  • Authentication sessions
  • Protecting routes
  • Database adapters
  • Configuring the Credentials Provider

Setting up Next Auth​

使用 npm install next-auth 安装 Next-Auth(Auth.js)。安装好后首先去 .env 中配置环境变量

DATABASE_URL="mysql://root:@localhost:3306/nextapp"
NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME="dzwywfjst"
# 添加下面两行
NEXTAUTH_URL=http:localhost:5050 # 你的项目位置
NEXTAUTH_SECRET=5xNi+cY1LdL1YnBWD9cUi4A34tTZJfUjKTlMCMjFcL0= # 随机数,可以使用 openssl random -base64 32 生成

设置完成后,在 api 文件夹下添加 auth/[...nextauth]/route.ts,并添加以下内容,为接下来做准备

api\auth[...nextauth]\route.ts

import NextAuth from "next-auth/next";const handler = NextAuth({});export { handler as GET, handler as POST };

设置 Provider​

本章代码链接

在Next Auth Provider可以看到 Next-Auth 支持多个 Authenticator Provider,包括 Google,Github,Facebook 等

创建项目​

此处以 Google 为例,首先进入 Google Credentials 页面新建一个 Project

Create Project

设置项目名称后点击创建即可

Set Project Name

如下图,点击配置 Consent Screen

Configure Consent Screen

首先设置为供外部使用

External

在弹出页面填写三个必须字段 应用名称用户支持电子邮件,以及最下面的开发者联系信息,其他字段都可选填,比如图片 logo 之类的

点击页面最下面的保存并继续,设置应用权限,一般只添加 email 和 profile 即可。再点击保存并继续,添加测试用户,把自己的账户添加即可。

Set Scope

最后保存返回信息中心即可

创建 OAuth​

在 凭据 页面点击创建 OAuth 客户端 ID

Create Credential

设置 OAuth,首先设置为 Web 应用,设置应用名,下方 JavaScript 来源设置为部署的端口(开发环境),再下方设置重定向的 URI,在Next Auth Google页面有写

Set OAuth

Callback URI

点击创建即可

Create Success

复制好客户端 id 和密钥备用

调用​

回到 .env 中添加 GOOGLE_CLIENT_ID 和 GOOGLE_CLIENT_SECRET

DATABASE_URL="mysql://root:@localhost:3306/nextapp"
NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME="dzwywfjst"
# 添加下面两行
NEXTAUTH_URL=http:localhost:5050 # 你的项目位置
NEXTAUTH_SECRET=5xNi+cY1LdL1YnBWD9cUi4A34tTZJfUjKTlMCMjFcL0= # 随机数,可以使用 openssl random -base64 32 生成
# 刚刚的客户端id 和 密钥
GOOGLE_CLIENT_ID=479267153395-gpqe25rbf62p0aj4h7icnfd01qt0p3qo.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=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

在 auth/[...nextauth]/route.ts,并添加以下内容(直接复制即可)

api\auth[...nextauth]\route.ts

import NextAuth from "next-auth";
import GoogleProvider from "next-auth/providers/google";const handler = NextAuth({providers: [GoogleProvider({clientId: process.env.GOOGLE_CLIENT_ID!,clientSecret: process.env.GOOGLE_CLIENT_SECRET!,}),],
});export { handler as GET, handler as POST };

在 Navbar.tsx 中添加一个 Link 到 login

NavBar.tsx

import Link from "next/link";
import React from "react";const NavBar = () => {return (<div className="flex bg-slate-200 p-5 space-x-3"><Link href="/" className="mr-5">Next.js</Link><Link href="/users">Users</Link>{/* Add this Link */}<Link href="/api/auth/signin">Login</Link></div>);
};export default NavBar;

回到浏览器,点击 login,即可看到如下页面

Google Login

由于某些魔法原因,next-auth 使用 google 一直在报 ERROR,笔者寻找多方也未解决,尝试使用 Github Provider 可行,故向读者推荐使用 Github Provider,并在下面给出演示

[next-auth][error][SIGNIN_OAUTH_ERROR]
https://next-auth.js.org/errors#signin_oauth_error outgoing request timed out after 3500ms {error: {message: 'outgoing request timed out after 3500ms',stack: 'RPError: outgoing request timed out after 3500ms\n' +.......name: 'RPError'},providerId: 'google',message: 'outgoing request timed out after 3500ms'
}

Github Provider​

进入Github OAuth App页面,新建 OAuth App

Github Create OAuth App

设置内容和 Google 内容差不多,Callback url 最后换成 Github 即可 http://localhost:5050/api/auth/callback/github

Github Set OAuth

点击创建凭证

Create Credential

IMPORTANT

注意,创建好后仅能在该页面复制一次,以后再也无法复制

Warning

回到 .env 中添加 GITHUB_CLIENT_ID 和 GITHUB_CLIENT_SECRET

DATABASE_URL="mysql://root:@localhost:3306/nextapp"
NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME="dzwywfjst"
# 添加下面两行
NEXTAUTH_URL=http:localhost:5050 # 你的项目位置
NEXTAUTH_SECRET=5xNi+cY1LdL1YnBWD9cUi4A34tTZJfUjKTlMCMjFcL0= # 随机数,可以使用 openssl random -base64 32 生成
# 刚刚的客户端id 和 密钥
GITHUB_CLIENT_ID=6f1433456dsfa526c
GITHUB_CLIENT_SECRET=ec8055183a9adfefsf0b305c282be6d55fe64f

修改 auth/[...nextauth]/route.ts 中的 provider 为 Github

import NextAuth from "next-auth";
import Github from "next-auth/providers/github";const handler = NextAuth({providers: [Github({clientId: process.env.GITHUB_CLIENT_ID!,clientSecret: process.env.GITHUB_CLIENT_SECRET!,}),],
});export { handler as GET, handler as POST };

保存,进入 Login 界面即可正常使用 Github 登录

Session​

Check Session​

本章代码链接

在浏览器中打开开发者工具,进入应用,选择 cookie,即可看到这里有一条 next-auth.session-token ,其本质为一个 json web token,为了查看这个 cookie,我们可以在 /api/auth 下新建 token/route.ts,并添加以下内容

import { getToken } from "next-auth/jwt";
import { NextRequest, NextResponse } from "next/server";export async function GET(request: NextRequest) {const token = await getToken({ req: request });return NextResponse.json(token);
}

去浏览器访问 http://localhost:5050/api/auth/token 即可看到如下内容

Json Web Token

其包含如用户名,邮箱,头像,过期时间等信息

Accessing Session from client​

本章代码链接

在用户端获取 session 信息需要用到 SessionProvider。我们首先创建一个新 component /auth/AuthProvider.tsx。将所有 children 用 SessionProvider 包起来

"use client";
import React, { ReactNode } from "react";
import { SessionProvider } from "next-auth/react";const AuthProvider = ({ children }: { children: ReactNode }) => {return (<><SessionProvider>{children}</SessionProvider></>);
};
export default AuthProvider;

然后回到根文件夹的 layout.tsx 中

  import "./globals.css";import type { Metadata } from "next";import { Inter } from "next/font/google";import NavBar from "./NavBar";
// 导入刚刚的 AuthProvider
+ import AuthProvider from "./auth/Provider";const inter = Inter({ subsets: ["latin"] });export const metadata: Metadata = {title: "Create Next App",description: "Generated by create next app",};export default function RootLayout({children,}: {children: React.ReactNode;}) {return (<html lang="en" data-theme="winter"><body className={inter.className}>
{/*将 body 里的内容都用 AuthProvider 包起来*/}
+         <AuthProvider><NavBar /><main className="p-5">{children}</main>
+         </AuthProvider></body></html>);}

之后到 NavBar 组件里获取 Session 内容

  "use client";// improt useSession
+ import { useSession } from "next-auth/react";import Link from "next/link";import React from "react";const NavBar = () => {// 使用 useSession() 来获取 Session 中的数据
+   const { status, data: session } = useSession();return (<div className="flex bg-slate-200 p-5 space-x-3"><Link href="/" className="mr-5">Next.js</Link><Link href="/users">Users</Link>{/*根据status的不同状态来渲染 "登录" 或者 "用户" 或 "加载中"*/}
+       {status === "loading" && <div>Loading...</div>}
+       {status === "authenticated" && <div>{session.user!.name}</div>}
+       {status === "unauthenticated" && (
+         <Link href="/api/auth/signin">Login</Link>
+       )}</div>);};export default NavBar;

此时回到浏览器,刷新即可看到,可以正常显示用户名了

Client Accessing Session

Accessing Session from server​

本章代码链接

在服务器端获取 session 也很简单,首先要先回到 api/auth/[...nextauth]/route.ts 中修改一下,将刚刚的 providers 作为一个 const export 出来,以便在其他页面使用(注意笔者使用的还是 Github 作为 Provider)

import NextAuth from "next-auth";
import Github from "next-auth/providers/github";
// import GoogleProvider from "next-auth/providers/google";export const authOptions = {providers: [Github({clientId: process.env.GITHUB_CLIENT_ID!,clientSecret: process.env.GITHUB_CLIENT_SECRET!,}),],
};const handler = NextAuth(authOptions);export { handler as GET, handler as POST };

然后在主页面的 page.tsx 中可以调用 getServerSession() 来获取 session

  import Link from "next/link";import ProductCard from "./components/ProductCard/ProductCard";// 导入 getServerSession 方法和刚刚的 authOptions 设置
+ import { getServerSession } from "next-auth";
+ import { authOptions } from "./api/auth/[...nextauth]/route";export default async function Home() {// 调用 getServerSession 来获取 session
+   const session = await getServerSession(authOptions);return (<><main>{/*直接调用session中的内容(user!中的!代表该变量不会为空)"*/}
+         <h1>Hello {session && session.user!.name}!</h1><Link href="/users">Users</Link><ProductCard /></main></>);}

最终显示效果如下

Server Accessing Session

Sign Out​

本章代码链接

使用一个 Link 跳转到 api/auth/signout 即可

  "use client";import { useSession } from "next-auth/react";import Link from "next/link";import React from "react";const NavBar = () => {const { status, data: session } = useSession();return (<div className="flex bg-slate-200 p-5 space-x-3"><Link href="/" className="mr-5">Next.js</Link><Link href="/users">Users</Link>{status === "loading" && <div>Loading...</div>}{/*跳转至 api/auth/signout 即可*/}
+       {status === "authenticated" && (
+         <div>
+           {session.user!.name}
+           <Link href="api/auth/signout" className="ml-3">
+             Sign Out
+           </Link>
+         </div>
+       )}{status === "unauthenticated" && (<Link href="/api/auth/signin">Login</Link>)}</div>);};export default NavBar;

最终效果如下

Sign Out

Protecting Route​

本章代码链接

有时候,我们需要防止用户在没有登录的情况下跳转至某些页面,比如想要直接使用 url 进入到 profile 页面,此时我们需要重定向到登录界面。在 Next.js 中内置了 MiddleWare 帮我们完成这个任务,我们不需要手动在每个界面自己写跳转。我们只需要在根目录(注意是和 app 同级目录,之前都是在 app 文件夹中)下添加 middleware.ts 添加设置即可,如下代码则表示所有以 /dashboard 开头的路由,都需要有 session。其最后一个字符代表子路由的层级

export { default } from "next-auth/middleware";export const config = {// *: zero or more// +: one or more// ?: zero or onematcher: ["/dashboard/:path*"],
};

Database Adapters​

本章代码链接

在Next-Auth Prisma页面可以找到,使用 npm i @next-auth/prisma-adapter 以安装 adapter

备注

Next-Auth 正在改名为 Auth.js,截止 2024.2.27,仍然可以使用上方 npm 指令安装,如果读者使用时出错,访问Next-Auth Prisma页面应该可以找到新的安装命令

安装好之后,配置 schema.prisma,同样在Next-Auth Prisma Schema页面可以找到教程,也可以把我下面的代码直接复制到 schema.prisma 中,再使用 npx prisma migrate dev 指令进行合并即可

schema.prisma配置

// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-initgenerator client {provider = "prisma-client-js"
}datasource db {provider = "mysql"url      = env("DATABASE_URL")
}model Account {id                 String  @id @default(cuid())userId             Stringtype               Stringprovider           StringproviderAccountId  Stringrefresh_token      String?  @db.Textaccess_token       String?  @db.Textexpires_at         Int?token_type         String?scope              String?id_token           String?  @db.Textsession_state      String?user User @relation(fields: [userId], references: [id], onDelete: Cascade)@@unique([provider, providerAccountId])
}model Session {id           String   @id @default(cuid())sessionToken String   @uniqueuserId       Stringexpires      DateTimeuser         User     @relation(fields: [userId], references: [id], onDelete: Cascade)
}model User {id            String    @id @default(cuid())name          String?email         String?   @uniqueemailVerified DateTime?image         String?accounts      Account[]sessions      Session[]
}model VerificationToken {identifier Stringtoken      String   @uniqueexpires    DateTime@@unique([identifier, token])
}

完成后在 api\auth[...nextauth]\route.ts 设置 PrismaAdapter

  import NextAuth, { NextAuthOptions } from "next-auth";import Github from "next-auth/providers/github";import GoogleProvider from "next-auth/providers/google";
+ import { PrismaAdapter } from "@next-auth/prisma-adapter";
+ import prisma from "@/prisma/client";export const authOptions: NextAuthOptions = {// 设置 PrismaAdapter
+   adapter: PrismaAdapter(prisma),providers: [GoogleProvider({clientId: process.env.GOOGLE_CLIENT_ID!,clientSecret: process.env.GOOGLE_CLIENT_SECRET!,}),Github({clientId: process.env.GITHUB_CLIENT_ID!,clientSecret: process.env.GITHUB_CLIENT_SECRET!,}),],session: {strategy: "jwt",},};const handler = NextAuth(authOptions);export { handler as GET, handler as POST };

再次尝试登陆后,即可在数据库中看到

Database Demo

CSDN 的排版/样式可能有问题,去我的博客查看原文系列吧,觉得有用的话, 给我的库点个star,关注一下吧

下一篇讲发送邮件

下一篇【Next.js 入门教程系列】08-发送邮件

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/445319.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于Spring Boot的医疗病历交互系统开发指南

第2章 设计技术与开发环境 2.1 相关技术介绍 2.1.1 B/S模式分析 C/S模式主要由客户应用程序(Client)、服务器管理程序(Server)和中间件(middleware)三个部件组成。客户应用程序是系统中用户与数据组件交互。服务器程序负责系统资源&#xff0c;如管理信息数据库的有效管理&…

使用Docker搭建WAF-开源Web防火墙VeryNginx

1、说明 VeryNginx 基于 lua_nginx_module(openrestry) 开发,实现了防火墙、访问统计和其他的一些功能。 集成在 Nginx 中运行,扩展了 Nginx 本身的功能,并提供了友好的 Web 交互界面。 文章目录 1、说明1.1、基本概述1.2、主要功能1.3、应用场景2、拉取镜像3、配置文件4、…

kafka-manager修改zookeeper端口号后启动仍然连接2181端口

问题描述&#xff1a; zookeeper默认端口号修改为了2182&#xff0c;kafka-manager的配置文件application.conf中也已经修改了zkhosts为新的端口号&#xff0c;然而启动kafka-manger时报错连接连接超时&#xff0c;发现连接的还是2181端口&#xff0c;很奇怪&#xff1f;&…

【D3.js in Action 3 精译_029】3.5 给 D3 条形图加注图表标签(上)

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第一部分 D3.js 基础知识 第一章 D3.js 简介&#xff08;已完结&#xff09; 1.1 何为 D3.js&#xff1f;1.2 D3 生态系统——入门须知1.3 数据可视化最佳实践&#xff08;上&#xff09;1.3 数据可…

C++题 十进制转二进制

文章目录 1. 使用C20 std::format2. 使用 std::bitset 类3. 手动实现十进制到二进制的转换反过来&#xff0c;手动二进制到十进制 VisualStudio2022使用C&#xff0c;进行十进制到二进制的转换&#xff0c;常见的实现方式 1. 使用C20 std::format 需要将VisualStudio默认的标准…

Linux高阶——0928—Github本地仓库与云端仓库关联

1、安装代理软件 steam 选择Github和系统代理模式&#xff0c;一键加速即可 2、 安装Git 3、访问Github网站&#xff0c;创建新用户 4、Github探索 &#xff08;1&#xff09;Explore探索标签 &#xff08;2&#xff09;工程结构 用户名/仓库名 自述文件&#xff0c;用markdo…

【笔记】I/O总结王道强化视频笔记

文章目录 从中断控制器的角度来理解整个中断处理的过程复习 处理器的中断处理机制**中断驱动I/O方式** printf——从系统调用到I/O控制方式的具体实现1轮询方式下输出一个字符串(程序查询)中断驱动方式下输出一个字符串中断服务程序中断服务程序与设备驱动程序之间的关系 DMA方…

线性代数在大一计算机课程中的重要性

线性代数在大一计算机课程中的重要性 线性代数是一门研究向量空间、矩阵运算和线性变换的数学学科&#xff0c;在计算机科学中有着广泛的应用。大一的计算机课程中&#xff0c;线性代数的学习为学生们掌握许多计算机领域的关键概念打下了坚实的基础。本文将介绍线性代数的基本…

数据库——创立表和库

数据库&#xff08;Database&#xff09;是一个用于存储、管理和检索数据的系统。它可以组织结构化数据&#xff0c;支持高效的存取和操作。数据库通常由一个数据库管理系统&#xff08;DBMS&#xff09;来支持&#xff0c;常见的DBMS包括&#xff1a; 关系数据库&#xff08;R…

Java创建型模式(二)——工厂模式(简单工厂模式、工厂方法模式、抽象工厂模式、工厂模式扩展等完整详解,附有代码——案例)

文章目录 五.工厂模式5.1 概述5.2简单工厂模式5.2.1 概述5.2.2 结构5.2.3 实现5.2.4 优缺点5.2.5 扩展—静态工厂 5.3 工厂方法模式5.3.1概述5.3.2 结构5.3.3 实现5.3.4 优缺点 5.4 抽象工厂模式5.4.1 概述5.4.2 结构5.4.3 实现5.4.4 优缺点5.4.5 使用场景 5.5 工厂模式扩展 五…

R语言机器学习算法实战系列(三)lightGBM算法(Light Gradient Boosting Machine)

文章目录 介绍原理:应用方向:教程下载数据加载R包导入数据数据预处理数据描述数据切割设置数据对象调节参数训练模型预测测试数据评估模型模型准确性混淆矩阵模型评估指标ROC CurvePRC Curve特征的重要性模型SHAP值解释保存模型总结系统信息介绍 LightGBM(Light Gradient B…

MyBatis-Plus 之 typeHandler 的使用

一、typeHandler 的使用 1、存储json格式字段 如果字段需要存储为json格式&#xff0c;可以使用JacksonTypeHandler处理器。使用方式非常简单&#xff0c;如下所示&#xff1a; 在domain实体类里面要加上&#xff0c;两个注解 TableName(autoResultMap true) 表示自动…

腾讯云-云直播

云直播&#xff08;Cloud Streaming Services&#xff09;为您提供极速、稳定、专业的直播云端处理服务&#xff0c;根据业务中不同直播场景的需求&#xff0c;云直播提供标准直播、快直播、慢直播和云导播台服务&#xff0c;分别针对大规模实时观看、高并发推流录制及超低延时…

数学建模算法与应用 第11章 偏最小二乘回归及其方法

目录 11.1 偏最小二乘回归概述 11.2 Matlab 偏最小二乘回归命令 Matlab代码示例&#xff1a;偏最小二乘回归 11.3 案例分析&#xff1a;化学反应中的偏最小二乘回归 Matlab代码示例&#xff1a;光谱数据的PLS回归 习题 11 总结 偏最小二乘回归&#xff08;Partial Least …

如何加密重要U盘?U盘怎么加密保护?

在日常生活中&#xff0c;我们常常使用U盘来存储和传输重要文件。然而&#xff0c;U盘的便携性也意味着它容易丢失或被盗。为了保护U盘中的数据安全&#xff0c;我们需要对U盘进行加密。本文将为您介绍如何加密重要U盘&#xff0c;以及U盘加密保护的方法。 BitLocker BitLocke…

动态规划——多状态动态规划问题

目录 一、打家劫舍 二、打家劫舍 II 三、删除并获得点数 四、粉刷房子 五、买卖股票的最佳时机含冷冻期 六、买卖股票的最佳时机含手续费 七、买卖股票的最佳时机III 八、买卖股票的最佳时机IV 一、打家劫舍 打家劫舍 第一步&#xff1a;确定状态表示 当我们每次…

『Mysql进阶』Mysql SQL语句性能分析(七)

目录 什么是Profile&#xff1f; 开启Profile功能 基本使用 分析案例 什么是Profile&#xff1f; Query Profiler是 MySQL 自带的一种 Query 诊断分析工具 &#xff0c;通过它可以分析出一条 SQL 语句的 硬件性能瓶颈 在什么地方。 通常我们是使用的 explain &#xff0c;…

企业内部文档安全外发如何挑选合适的外发系统?

企业文档的外发不仅关系到运营效率&#xff0c;更是信息安全的重要组成部分。面对B2B模式下文档交换的普遍性和重要性&#xff0c;企业内部文档的安全外发成为了众多公司关注的重点之一。 随着互联网技术的发展&#xff0c;企业之间的合作越来越紧密&#xff0c;文档的交流也变…

springboot+react实现移动端相册(上传图片到oss/ 批量删除/ 查看图片详情等功能)

相册页面及功能展示&#xff1a; react前端结构及代码&#xff1a; Java后端结构及代码 数据库结构&#xff1a; photo&#xff1a; user 这是首个利用AI自有知识构建的简易相册系统&#xff0c;项目是react构造前端spring boot构造后端。 前端有四个主要页面&#xff1…

Compose第六弹 对话框与弹窗

1.compose中怎么使用对话框&#xff1f; 2.怎么显示Popup弹窗&#xff1f; 一、Compose显示对话框 二、Popup Popup就类似以前的Popupwindow&#xff0c;我们可以看到其实上面的DropdownMenu是Popup的一个具体实现。 2.1 Popup定义 Popup的定义如下&#xff1a; Composable…