我的远程实习(六) | 一个demo讲清Auth.js国外平台登录鉴权👈|nextjs
前言
前些时候 ,远程实习要求实现鉴权登录 , 采用 Auth.js 可用于在 Nextjs 项目中实现登录鉴权 ,今天我写一个 demo , 为大家展示一下 auth 鉴权的数据流转 ~
我们首先介绍一下: NextAuth.js 是一个专为 Next.js 应用设计的灵活且易于使用认证库,它极大地简化了添加登录、注册、登出等认证功能的过程。该库以其灵活性和强大的功能而闻名,支持多种认证方式,包括电子邮件与密码、OAuth 2.0 提供商(如 Google、GitHub、Facebook 等),以及自定义提供商。
主要特点
- 丰富的内置提供者:支持众多 OAuth 和 OpenID Connect 提供商,方便快捷地与第三方服务集成。
- 会话管理:提供简明的 API 来处理用户会话,轻松获取当前用户的会话信息。
- 数据库兼容性:支持与多种数据库集成,适用于存储用户数据,并能无缝对接无头 CMS 和自定义后端。
- 多语言支持:根据用户的语言偏好显示错误消息及其他文本,增强用户体验。
- 可定制页面:允许开发者创建符合应用设计风格的自定义登录、注册或错误页面。
- 安全优先:采用一系列安全默认设置,帮助保护应用免受常见的安全威胁。
- API 路由整合:利用 Next.js 的 API 路由机制来实现身份验证逻辑,让开发者可以自由创建用于登录、登出等操作的自定义端点。
- 会话管理选项:提供选择,既可以通过 JSON Web Tokens (JWT) 实现无状态会话管理,也可以选择基于数据库的会话管理。
- 适配器支持:为了满足将用户数据持久化到数据库的需求,NextAuth.js 提供了与不同数据库系统(如 Prisma、TypeORM 等)集成的适配器。
demo 效果展示
Gitee:gitee.com/luli1314520…
开源不易 , 点个小小赞支持下 ~
认证演示项目登录流程分析
项目结构
项目使用Next.js框架构建,采用App Router架构,主要目录结构:
-
/app
- 前端页面和API路由-
/app/auth/signin
- 登录页面 -
/app/api/auth/[...nextauth]
- NextAuth API路由
-
-
/auth
- NextAuth配置 -
/services
- 业务逻辑层 -
/models
- 数据访问层 -
/types
- 类型定义 -
/lib
- 工具函数
认证方案
项目使用NextAuth.js实现第三方OAuth认证,支持以下登录方式:
- Google OAuth登录
- GitHub OAuth登录
认证数据流转图
┌─────────────┐ ┌─────────────────┐ ┌────────────────────┐
│ │ │ │ │ │
│ 用户界面 │─────▶│ NextAuth API │─────▶│ OAuth提供商 │
│ (客户端) │◀─────│ (服务端路由) │◀─────│ (Google/GitHub) │
│ │ │ │ │ │
└─────────────┘ └─────────────────┘ └────────────────────┘
│ │ │
│ │ │
▼ ▼ │
┌─────────────┐ ┌─────────────────┐ │
│ │ │ │ │
│ 会话状态 │◀────▶│ 数据存储 │◀──────────────┘
│ (JWT) │ │ (用户信息) │
│ │ │ │
└─────────────┘ └─────────────────┘
数据流转详解
-
用户界面 → NextAuth API → OAuth提供商
- 用户在前端界面点击登录按钮,触发认证流程
- NextAuth API构建OAuth授权URL并重定向用户
- 用户被引导至第三方OAuth提供商(Google/GitHub)进行身份验证
-
OAuth提供商 → NextAuth API → 数据存储
- 用户在OAuth提供商完成身份验证
- 提供商重定向回NextAuth回调URL,附带授权码
- NextAuth API使用授权码换取用户信息
- 用户信息被保存到数据存储中
-
NextAuth API → 会话状态
- 认证成功后,NextAuth创建JWT令牌
- JWT包含必要的用户信息和认证元数据
- 令牌加密并存储在HTTP-only cookie中
-
会话状态 ↔ 用户界面
- 前端通过
useSession
钩子或getSession
函数获取会话状态 - 会话状态包含用户身份和权限信息
- 用户界面根据会话状态调整显示内容(如显示用户资料)
- 前端通过
-
会话状态 ↔ 数据存储
- JWT令牌中包含用户标识符(如UUID)
- 可通过标识符从数据存储中获取完整用户信息
- 会话更新时可能涉及数据存储的变更(如更新登录时间)
登录流程(前端到后端)
1. 前端登录入口
文件: app/auth/signin/page.tsx
登录页面是服务端组件,显示登录按钮并检查用户是否已登录:
export default async function SignInPage({
searchParams,
}: {
searchParams: { callbackUrl: string | undefined };
}) {
const session = await auth();
if (session) {
return redirect(searchParams.callbackUrl || "/");
}
// 登录页面UI
}
此组件对应数据流转图中的用户界面(客户端),负责展示登录界面并检查会话状态。
2. 客户端登录按钮
文件: app/auth/signin/client.tsx
客户端组件,处理登录按钮点击事件:
export function SignInButton({
provider,
callbackUrl,
children
}: {
provider: string;
callbackUrl?: string;
children: React.ReactNode;
}) {
return (
<button
onClick={() => signIn(provider, { callbackUrl: callbackUrl || '/' })}
className="..."
>
{provider === 'google' && <FaGoogle className="..." />}
{provider === 'github' && <FaGithub className="..." />}
<span>{children}</span>
</button>
);
}
此组件触发用户界面→NextAuth API的数据流,调用 signIn
函数发起认证请求。
3. NextAuth API路由
文件: app/api/auth/[...nextauth]/route.ts
处理NextAuth的API请求:
import NextAuth from "next-auth";
import { authOptions } from "@/auth/config";
const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };
此文件对应数据流转图中的NextAuth API(服务端路由),处理所有认证相关的HTTP请求,包括:
- 认证请求(重定向到OAuth提供商)
- 回调处理(接收OAuth提供商的回调)
- 会话查询(前端获取会话状态)
4. NextAuth配置
文件: auth/config.ts
配置NextAuth认证选项,包括:
- 认证提供商(Google、GitHub)
- 登录回调
- JWT处理
- Session处理
关键代码:
export const authOptions: NextAuthConfig = {
providers,
pages: {
signIn: "/auth/signin",
},
callbacks: {
async signIn({ user, account, profile }) { ... },
async redirect({ url, baseUrl }) { ... },
async session({ session, token }) { ... },
async jwt({ token, user, account }) { ... },
},
};
这个配置文件定义了NextAuth API如何与OAuth提供商和数据存储交互,以及如何处理会话状态。
5. NextAuth实例
文件: auth/index.ts
创建NextAuth实例并导出相关函数:
import NextAuth from "next-auth";
import { authOptions } from "./config";
export const { handlers, signIn, signOut, auth } = NextAuth(authOptions);
这些导出的函数促成了数据流转图中的多个流程:
-
signIn
:用户界面→NextAuth API -
auth
:NextAuth API→会话状态 -
signOut
:用户界面→NextAuth API→会话状态(清除)
6. 用户信息处理
文件: services/user.ts
处理用户信息保存逻辑:
export async function saveUser(user: User) {
try {
const existUser = await findUserByEmail(user.email);
if (!existUser) {
await insertUser(user);
} else {
user.id = existUser.id;
user.uuid = existUser.uuid;
user.created_at = existUser.created_at;
}
return user;
} catch (e) {
throw e;
}
}
此服务对应数据流转图中的NextAuth API→数据存储流程,负责将OAuth提供商返回的用户信息持久化到数据存储中。
7. 数据存储
文件: models/user.ts
示例项目使用内存数组存储用户信息,实际项目应使用数据库:
// 演示用简化版本,实际项目中应使用数据库
const users: User[] = [];
export async function findUserByEmail(email: string): Promise<User | null> { ... }
export async function findUserByUuid(uuid: string): Promise<User | null> { ... }
export async function insertUser(user: User): Promise<User> { ... }
此模块实现了数据流转图中的**数据存储(用户信息)**组件,提供用户数据的CRUD操作。
登录流程详解
-
用户点击登录按钮:
- 前端调用
signIn(provider)
函数 - NextAuth.js将用户重定向到第三方OAuth提供商(Google/GitHub)
- 数据流:用户界面→NextAuth API→OAuth提供商
- 前端调用
-
第三方认证:
- 用户在第三方平台完成认证
- 第三方平台将用户重定向回应用的回调URL
- 数据流:OAuth提供商→NextAuth API
-
处理回调:
- NextAuth.js API接收回调请求
- 调用
jwt
回调处理令牌 - 保存用户信息到后端存储
- 数据流:NextAuth API→数据存储和NextAuth API→会话状态
-
创建会话:
- 调用
session
回调构建会话信息 - 返回包含用户信息的会话对象
- 数据流:会话状态↔用户界面
- 调用
-
完成登录:
- 用户被重定向到指定的回调URL或首页
- 前端可通过
useSession
钩子或auth()
函数访问会话信息 - 数据流:会话状态↔用户界面和会话状态↔数据存储
JWT与会话状态管理
JWT(JSON Web Token)在认证流程中扮演核心角色,对应数据流转图中的**会话状态(JWT)**节点:
-
JWT创建:
- 用户成功认证后,NextAuth创建包含用户信息的JWT令牌
- JWT中存储必要的用户信息(如UUID、头像URL等)
- 数据流:NextAuth API→会话状态
-
JWT存储:
- JWT令牌加密后存储在HTTP-only cookie中
- 浏览器每次请求自动发送cookie,实现无状态认证
- 数据流:会话状态↔用户界面
-
会话构建:
- 服务端通过
auth()
函数解析JWT令牌获取会话信息 - 客户端通过
useSession()
钩子访问会话状态 - 数据流:会话状态↔用户界面
- 服务端通过
-
会话与数据存储交互:
- 会话中的用户标识可用于从数据存储获取完整用户信息
- 可通过会话中的用户ID更新数据存储中的用户信息
- 数据流:会话状态↔数据存储
类型扩展
NextAuth类型扩展,支持JWT和Session中的自定义字段:
declare module "next-auth" {
interface JWT {
user?: {
uuid?: string;
nickname?: string;
avatar_url?: string;
created_at?: string;
};
}
interface Session {
user: {
uuid?: string;
email?: string | null;
name?: string | null;
nickname?: string | null;
avatar_url?: string | null;
created_at?: string | null;
}
}
}
用户类型定义,对应数据存储中的用户数据结构:
export interface User {
id?: number;
uuid?: string;
email: string;
created_at?: string;
nickname: string;
avatar_url: string;
signin_type?: string;
signin_ip?: string;
signin_provider?: string;
signin_openid?: string;
}
安全考虑
- 环境变量:OAuth客户端ID和密钥存储在环境变量中
- 重定向检查:验证重定向URL的合法性
- JWT令牌:使用JWT保存会话状态,加密存储防篡改
- 无密码存储:使用OAuth方式不需要存储用户密码
- HTTP-only Cookie:JWT存储在HTTP-only cookie中,防止JavaScript访问
- CSRF保护:NextAuth内置CSRF令牌验证机制
数据流转优化建议
-
数据库集成:
- 将内存存储替换为持久化数据库(MongoDB、PostgreSQL等)
- 优化数据存储与NextAuth API的交互性能
-
令牌刷新机制:
- 实现OAuth访问令牌自动刷新功能
- 延长用户会话有效期,减少重复登录
-
缓存层引入:
- 在数据存储与会话状态之间添加缓存层(如Redis)
- 减轻数据库负担,提高频繁会话查询性能
-
前端状态管理:
- 优化前端会话状态管理,减少不必要的API调用
- 实现优雅的会话过期处理和自动重新认证