Next.js 14中React Native移动端应用的API授权方案咨询
双策略适配方案(Web Session + 移动端JWT)
你的思路完全可行,NextAuth支持灵活的认证策略配置,可以同时满足Web端的Session/Cookie需求和移动端的JWT授权。以下是具体实现步骤:
1. 配置NextAuth区分客户端类型
在app/api/auth/[...nextauth]/route.js中,通过请求头识别客户端类型,分别返回对应的认证凭证:
import NextAuth from "next-auth"; import CredentialsProvider from "next-auth/providers/credentials"; import jwt from "jsonwebtoken"; const SECRET = process.env.NEXTAUTH_SECRET || "your-secret-key"; export const authOptions = { providers: [ CredentialsProvider({ async authorize(credentials) { // 替换为你的用户校验逻辑(如查询数据库) const user = { id: "1", name: "Test User", email: "test@example.com" }; if (user) return user; return null; }, }), ], session: { strategy: "jwt" }, callbacks: { async jwt({ token, user }) { const isMobile = req.headers.get("X-Client-Type") === "mobile"; // 为移动端生成专用JWT if (user && isMobile) { const mobileToken = jwt.sign({ userId: user.id }, SECRET, { expiresIn: "7d" }); token.mobileToken = mobileToken; } return token; }, async session({ session, token }) { const isMobile = req.headers.get("X-Client-Type") === "mobile"; // 给移动端返回JWT,Web端返回默认会话信息 if (isMobile) { session.mobileToken = token.mobileToken; } return session; }, }, secret: SECRET, }; const handler = NextAuth(authOptions); export { handler as GET, handler as POST };
2. Web端认证实现
Web端直接使用NextAuth官方API,自动处理Cookie会话:
- 登录:调用
signIn("credentials", { email, password }) - 获取会话:使用
useSession()钩子 - API路由验证:通过
getServerSession(authOptions)判断用户权限
// app/api/protected/route.js import { getServerSession } from "next-auth/next"; import { authOptions } from "../auth/[...nextauth]/route"; export async function GET() { const session = await getServerSession(authOptions); if (!session) return new Response("Unauthorized", { status: 401 }); return new Response(JSON.stringify({ user: session.user }), { status: 200 }); }
3. 移动端JWT授权实现
React Native端登录时标记客户端类型,获取JWT后存入本地存储:
// 移动端登录请求 async function login(email, password) { const res = await fetch("http://your-nextjs-app/api/auth/signin/credentials", { method: "POST", headers: { "Content-Type": "application/json", "X-Client-Type": "mobile", }, body: JSON.stringify({ email, password, callbackUrl: "http://localhost:3000" }), }); const data = await res.json(); if (data.mobileToken) { await AsyncStorage.setItem("authToken", data.mobileToken); } } // 移动端带JWT请求API async function fetchProtectedData() { const token = await AsyncStorage.getItem("authToken"); const res = await fetch("http://your-nextjs-app/api/protected", { headers: { Authorization: `Bearer ${token}`, }, }); return res.json(); }
移动端API验证逻辑
在Next.js API路由中同时兼容Web Session和移动端JWT验证:
// app/api/protected/route.js import jwt from "jsonwebtoken"; import { getServerSession } from "next-auth/next"; import { authOptions } from "../auth/[...nextauth]/route"; const SECRET = process.env.NEXTAUTH_SECRET || "your-secret-key"; export async function GET(req) { // 优先校验Web端Session const session = await getServerSession(authOptions); if (session) { return new Response(JSON.stringify({ user: session.user }), { status: 200 }); } // 校验移动端JWT const authHeader = req.headers.get("Authorization"); if (!authHeader || !authHeader.startsWith("Bearer ")) { return new Response("Unauthorized", { status: 401 }); } const token = authHeader.split(" ")[1]; try { const decoded = jwt.verify(token, SECRET); const user = { id: decoded.userId, name: "Test User" }; return new Response(JSON.stringify({ user }), { status: 200 }); } catch (err) { return new Response("Invalid token", { status: 401 }); } }
更优方案:统一用JWT(Web+移动端)
如果想简化后端逻辑,推荐统一使用JWT策略:
- Web端:NextAuth自动将JWT存储在HttpOnly Cookie中,和Session模式一样能防XSS攻击
- 移动端:将JWT存入AsyncStorage,请求时携带Authorization头
配置NextAuth统一JWT策略
// app/api/auth/[...nextauth]/route.js import NextAuth from "next-auth"; import CredentialsProvider from "next-auth/providers/credentials"; export const authOptions = { providers: [ CredentialsProvider({ async authorize(credentials) { // 用户校验逻辑 const user = { id: "1", name: "Test User", email: "test@example.com" }; return user; }, }), ], session: { strategy: "jwt" }, callbacks: { async jwt({ token, user }) { if (user) token.userId = user.id; return token; }, async session({ session, token }) { session.user.id = token.userId; // 可选:给移动端返回原始JWT if (req.headers.get("X-Client-Type") === "mobile") { session.token = token; } return session; }, }, secret: process.env.NEXTAUTH_SECRET, }; const handler = NextAuth(authOptions); export { handler as GET, handler as POST };
这种方案下,Web端依然可以用useSession和getServerSession,移动端直接使用返回的JWT,后端无需区分客户端类型,维护成本更低。
内容的提问来源于stack exchange,提问作者Ahmad Malik
相关产品推荐
相关产品推荐

