环境 环境 系统: 操作系统:macOS 14.3.1 CPU:(10)arm64苹果M1 Pro 内存:174.97 MB / 16.00 GB 外壳:5.9 - /bin/zsh 二进制文件: 节点:18.17.1 - ~/.nvm/versions/node/v18.17.1/bin/node 纱线:1.22.19 - /usr/local/bin/yarn npm:10.2.4 - ~/.nvm/versions/node/v18.17.1/bin/npm 浏览器: 勇敢的浏览器:121.1.62.156 铬:121.0.6167.184 Safari:17.3.1
我正在将 Amplify 与 NextAuth V5 结合使用。目前,我面临一个问题,即我没有指定 NEXTAUTH_URL。这在 Amplify 上似乎有问题,因为它仍然引用回本地主机。然而,主要问题是中间件没有为 auth.req 提供正确的输出。
auth.req 给我“消息”:“服务器配置存在问题。检查服务器日志以获取更多信息。”
有趣的是,我部署的代码在 Vercel 上完美运行,无需指定 NEXTAUTH_URL,并且中间件运行完美。我怀疑中间件在 Amplify 上的解释方式可能存在问题。
详细信息:我在 .env 中使用 NEXTAUTH_SECRET,但没有使用 NEXTAUTH_URL。 NEXTAUTH_SECRET 可以在中间件中读取,因此问题是无法在 amplify 上找到 .env 变量。
我也在使用 Prisma 和 Mongodb 适配器。
预期行为 如果用户已登录,则 auth.req 应返回用户;如果未登录,则应返回 null,而不是消息错误。
不应使用本地主机,而应使用我正在使用的子域(即 app.DOMAIN.com 或 dev.DOMAIN.com)
src/middleware.ts
import NextAuth from 'next-auth';
import authConfig from '@/auth.config';
import {
DEFAULT_LOGIN_REDIRECT,
apiAuthPrefix,
authRoutes,
publicRoutes,
} from './routes';
const { auth } = NextAuth(authConfig);
/* @ts-ignore */
export default auth((req) => {
const { nextUrl } = req;
if (nextUrl.pathname.startsWith('/ingest')) {
console.log('hit hit');
return null;
}
const isLoggedIn = !!req.auth;
console.log('isLoggedIn', isLoggedIn);
const isApiAuthRoute = nextUrl.pathname.startsWith(apiAuthPrefix);
const isPublicRoute = publicRoutes.includes(nextUrl.pathname);
const isAuthRoute = authRoutes.includes(nextUrl.pathname);
console.log('isApiAuthRoute', isApiAuthRoute);
console.log('isPublicRoute', isPublicRoute);
console.log('isAuthRoute', isAuthRoute);
if (isApiAuthRoute) {
return null;
}
if (isAuthRoute) {
if (isLoggedIn) {
return Response.redirect(new URL(DEFAULT_LOGIN_REDIRECT, nextUrl));
}
return null;
}
if (!isLoggedIn && !isPublicRoute) {
let callbackUrl = nextUrl.pathname;
if (nextUrl.search) {
callbackUrl += nextUrl.search;
}
const encodedCallbackUrl = encodeURIComponent(callbackUrl);
return Response.redirect(
new URL(`/?callbackUrl=${encodedCallbackUrl}`, nextUrl),
);
}
return null;
// req.auth
});
// Optionally, don't invoke Middleware on some paths
export const config = {
// matcher: ['/((?!.+\\.[\\w]+$|_next).*)', '/', '/(api|trpc)(.*)'],
matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
};
src/auth.ts
import NextAuth from 'next-auth';
import { UserRole } from '@prisma/client';
import { PrismaAdapter } from '@auth/prisma-adapter';
import { db } from '@/lib/db';
import authConfig from '@/auth.config';
import { getUserById } from '@/data/user';
import { getTwoFactorConfirmationByUserId } from '@/data/two-factor-confirmation';
import { getAccountByUserId } from './data/account';
export const {
auth,
signIn,
signOut,
unstable_update,
handlers: { GET, POST },
} = NextAuth({
trustHost: true,
logger: {
debug: console.log,
error: console.error,
warn: console.warn,
},
debug: true,
pages: {
signIn: '/',
error: '/auth/error',
},
events: {
async linkAccount({ user }) {
await db.user.update({
where: { id: user.id },
data: { emailVerified: new Date() },
});
},
},
callbacks: {
async signIn({ user, account }) {
// Allow OAuth without email verification
if (account?.provider !== 'credentials') return true;
const existingUser = await getUserById(user.id as string);
// Prevent sign in without email verification
if (!existingUser?.emailVerified) return false;
if (existingUser.isTwoFactorEnabled) {
const twoFactorConfirmation = await getTwoFactorConfirmationByUserId(
existingUser.id,
);
if (!twoFactorConfirmation) return false;
// Delete two factor confirmation for next sign in
await db.twoFactorConfirmation.delete({
where: { id: twoFactorConfirmation.id },
});
}
return true;
},
async session({ token, session }) {
if (token.sub && session.user) {
session.user.id = token.sub;
}
if (token.role && session.user) {
session.user.role = token.role as UserRole;
}
if (session.user) {
session.user.isTwoFactorEnabled = token.isTwoFactorEnabled as boolean;
}
if (session.user) {
session.user.family_name = token.family_name as string;
session.user.given_name = token.given_name as string;
session.user.email = token.email as string;
session.user.isOAuth = token.isOAuth as boolean;
session.user.completedOnboarding = token.completedOnboarding as boolean;
session.user.betaAccess = token.betaAccess as boolean;
session.user.dailyMessageCooldownCounter =
token.dailyMessageCooldownCounter as Date;
session.user.dailyMessageCount = token.dailyMessageCount as number;
session.user.stripe_customer_id = token.stripe_customer_id as string;
}
return session;
},
async jwt({ token }) {
if (!token.sub) return token;
const existingUser = await getUserById(token.sub);
if (!existingUser) return token;
const existingAccount = await getAccountByUserId(existingUser.id);
token.isOAuth = !!existingAccount;
token.family_name = existingUser.family_name;
token.given_name = existingUser.given_name;
token.email = existingUser.email;
token.role = existingUser.role;
token.isTwoFactorEnabled = existingUser.isTwoFactorEnabled;
token.completedOnboarding = existingUser.completedOnboarding;
token.betaAccess = existingUser.betaAccess;
token.dailyMessageCooldownCounter =
existingUser.dailyMessageCooldownCounter;
token.dailyMessageCount = existingUser.dailyMessageCount;
token.stripe_customer_id = existingUser.stripe_customer_id;
return token;
},
},
adapter: PrismaAdapter(db),
session: { strategy: 'jwt' },
...authConfig,
});
我遇到的两个错误:
�[31m[auth][error]�[0m UntrustedHost: Host must be trusted. URL was: https://dev.xyz.com/api/auth/session .Read more at https://errors.authjs.dev#untrustedhost
req {
"sourcePage": "/src/middleware",
"message": "There was a problem with the server configuration. Check the server logs for more information."
}
同样,部署到 Vercel 时一切正常,但部署到 Amplify 时则不然。任何帮助将不胜感激!
我尝试了我能想到的一切。每当我放置 NEXTAUTH_URL 时,它都无法解决 amplify 上的 /src/middlware 问题。
然后我在没有 NEXTAUTH_URL 的情况下部署到 vercel,它工作得很好。我认为问题出在 Amplify 上的某些配置上。
您需要在环境变量中更新或添加这些内容,如下所示:
在
.env.production
或 env.local
文件中
NEXTAUTH_URL=http://YOUR_LOCAL_OR_DEPLOYED_HOST_URL:HOST_PORT
AUTH_TRUST_HOST=http://YOUR_LOCAL_OR_DEPLOYED_HOST_URL:HOST_PORT
结果如下:
NEXTAUTH_URL=http://192.152.1.1:3000
AUTH_TRUST_HOST=ttp://192.152.1.1:3000