背景
因为升级到了Next-auth:5.0,鉴权结构变了,middleware的代码如下:
import { auth as middleware } from "@/lib/auth";
export const config = {
matcher: `/admin/:path*`,
// 不是管理员就跳转到主页
};
export default middleware;
其中auth文件如下:
import NextAuth from "next-auth";
import Credentials from "next-auth/providers/credentials";
import GithubProvider from "next-auth/providers/github";
import { PrismaAdapter } from "@auth/prisma-adapter";
import { NODE_ENV } from "@/config";
import { PATHS } from "@/constants";
import { getUserByEmailAndPassword } from "@/features/auth";
import { prisma } from "./prisma";
import { isAdmin, myLog } from "./utils";
export const runtime = "nodejs";
export const { handlers, auth, signOut, signIn } = NextAuth({
adapter: PrismaAdapter(prisma),
providers: [
GithubProvider,
Credentials({
// You can specify which fields should be submitted, by adding keys to the `credentials` object.
// e.g. domain, username, password, 2FA token, etc.
credentials: {
email: { label: "email", type: "email" },
password: { label: "password", type: "password" },
},
authorize: async (credentials) => {
try {
// 避免在这里直接打印 credentials
const { email, password } = credentials as {
email: string;
password: string;
};
// myLog("credentials", JSON.stringify(credentials));
const user = await getUserByEmailAndPassword(email, password);
// myLog("user", JSON.stringify(user));
return {
id: user.id,
email: user.email,
name: user.name,
};
} catch (error) {
return null;
}
},
}),
],
// 解决这个错误:Error: PrismaClient is not configured to run in Vercel Edge Functions or Edge Middleware.
// 参考:https://github.com/prisma/prisma/issues/21310#issuecomment-1840428931
session: { strategy: "jwt" },
trustHost: true,
pages: {
signIn: PATHS.AUTH_SIGN_IN,
},
debug: NODE_ENV === "development",
callbacks: {
// signin
async signIn({ user }) {
// myLog("signIn", user);
// 模拟promise
return new Promise((resolve) => resolve(true));
},
session({ session, token }) {
myLog("session", session, token);
if (session.user && token?.sub) {
session.user.id = token.sub;
}
return session;
},
authorized({ request, auth }) {
myLog("authorized", request, auth);
// 将来用作 Next.js middleware,如果是访问后台页面,校验是否登录
if (request.nextUrl.pathname.startsWith(PATHS.ADMIN_HOME)) {
// 是否是管理员
if (!isAdmin(auth?.user?.email)) {
return Response.redirect(new URL(PATHS.SITE_HOME, request.url));
} else {
return true;
}
}
// 其它路径直接放行
return true;
},
},
});
然后因为getUserByEmailAndPassword这个方法里有用到redis,就导致报错了····
这让我很是疑惑啊,middleware 是一个中间件,只能用于EdgeRuntime,但是EdgeRuntime不能够使用io-redis,怎么办呢?
解决方式
绕过middleware中间件
新建文件
参考:https://stackoverflow.com/questions/78713102/using-redis-with-auth-js-and-next-js-middleware-on-edge-runtime-dns-module-er我们可以在 Next.js 的 Edge 运行时使用数据库函数吗?当然可以,但也不能直接使用。我找到了一个解决方案,一种方法是创建一个 API 路由处理程序,并在 Edge 运行时使用 fetch 来实现。
在 auth.js 中,您可以创建一个独立的 auth.config.ts 文件(该文件不会执行任何边缘运行时不支持的数据库操作) 官方解释:
https://authjs.dev/guides/edge-compatibility#the-solution
关于在middleware里拿不到数据:
参考issue:https://github.com/nextauthjs/next-auth/issues/9836