NextAuth 与 Google 提供者以及自定义的后端 API 结合进行身份验证
2024-06-12
NextAuth 结合 Google 身份验证提供者和自定义后端 API 实现用户身份验证,包括安装 NextAuth、配置 Google Provider、使用环境变量、保护页面和 API 路由,以及后端使用 Go 和 Gin 框架处理验证和生成自定义 token。
-
安装 NextAuth:
在你的 Next.js 项目中安装 NextAuth 和所需的依赖项:npm install next-auth
-
配置 Google Provider:
在pages/api/auth/[...nextauth].js
文件中配置 NextAuth,添加 Google Provider,并配置相关的回调函数。import NextAuth from "next-auth"; import GoogleProvider from "next-auth/providers/google"; export default NextAuth({ providers: [ GoogleProvider({ clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, }) ], callbacks: { async jwt({ token, account, profile }) { // 初次登录时,将 JWT token 保存到自定义后端 if (account && profile) { const res = await fetch("https://your-backend-api.com/auth/google", { method: 'POST', headers: { "Content-Type": "application/json" }, body: JSON.stringify({ idToken: account.id_token, profile, }) }); const data = await res.json(); // 将后端返回的自定义 token 保存到 NextAuth token 中 token.backendToken = data.token; } return token; }, async session({ session, token }) { // 在会话对象中包含自定义 token session.user.backendToken = token.backendToken; return session; } }, pages: { signIn: '/auth/signin', } });
-
在环境变量中配置 Google 客户端 ID 和密钥:
在你的.env.local
文件中添加以下环境变量:GOOGLE_CLIENT_ID=your-google-client-id GOOGLE_CLIENT_SECRET=your-google-client-secret
-
保护页面或 API 路由:
使用 NextAuth 提供的getSession
或useSession
来保护你的页面或 API 路由,并通过自定义 token 访问后端 API。// 在页面组件中使用 useSession import { useSession } from "next-auth/react"; export default function ProtectedPage() { const { data: session, status } = useSession(); if (status === "loading") { return <div>Loading...</div>; } if (!session) { return <div>Access Denied</div>; } return ( <div> <h1>Protected Page</h1> <p>Welcome, {session.user.name}</p> </div> ); }
// 在 API 路由中使用 getSession import { getSession } from "next-auth/react"; export default async (req, res) => { const session = await getSession({ req }); if (!session) { res.status(401).json({ message: "Unauthorized" }); } else { const backendToken = session.user.backendToken; // 使用 backendToken 访问自定义后端 API const response = await fetch("https://your-backend-api.com/protected-route", { method: 'GET', headers: { Authorization: `Bearer ${backendToken}` }, }); const data = await response.json(); res.status(200).json(data); } };
后端配置(Go + Gin)
-
创建一个 Go 项目并安装 Gin:
go mod init your-backend go get -u github.com/gin-gonic/gin
-
在你的主文件(例如
main.go
)中配置 Gin 路由,并处理/auth/google
路由:package main import ( "encoding/json" "net/http" "github.com/gin-gonic/gin" ) type GoogleAuthRequest struct { IDToken string `json:"idToken"` Profile map[string]interface{} `json:"profile"` } func main() { r := gin.Default() r.POST("/auth/google", func(c *gin.Context) { var req GoogleAuthRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // 验证 ID Token (此处省略,假设已经验证通过) // 使用 req.IDToken 和 req.Profile 处理用户信息 // 生成自定义 token,示例中简单返回一个静态 token customToken := "your-custom-token" c.JSON(http.StatusOK, gin.H{"token": customToken}) }) r.Run(":8080") // 监听并在 0.0.0.0:8080 上启动服务 }
后端配置(Go + Gin)加上 验证
-
使用 Google 的验证库验证
idtoken
:package main import ( "context" "encoding/json" "net/http" "github.com/gin-gonic/gin" "google.golang.org/api/idtoken" ) type GoogleAuthRequest struct { IDToken string `json:"idToken"` Profile map[string]interface{} `json:"profile"` } func main() { r := gin.Default() r.POST("/auth/google", func(c *gin.Context) { var req GoogleAuthRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // 验证 ID Token tokenInfo, err := idtoken.Validate(context.Background(), req.IDToken, "your-google-client-id") if err != nil { c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid ID token"}) return } // 使用 tokenInfo 和 req.Profile 处理用户信息 // tokenInfo 中包含了用户的身份信息,可以进一步验证和使用 // 生成自定义 token,示例中简单返回一个静态 token customToken := "your-custom-token" c.JSON(http.StatusOK, gin.H{"token": customToken}) }) r.Run(":8080") // 监听并在 0.0.0.0:8080 上启动服务 }
-
添加
google.golang.org/api/idtoken
依赖:go get google.golang.org/api/idtoken