“会话 cookie 超出允许的 4096 字节。”-从 14.1.0 升级 nextJs 14.1.4 后出现此 Next Auth 错误

问题描述 投票:0回答:1

我使用 nextJs 作为前端,express 作为后端。对于身份验证,我正在使用 Next-Auth。

当我从 13.5 升级 nextJs 14.1.0 时仍然没问题,但昨天我将下一个应用程序更新为最新版本(v14.1.4),并且收到了 auth api 错误。然后,我再次恢复到以前的版本(14.1.0)并解决了错误。但尝试登录时出现新错误。

在控制台中,我得到这个: next auth error

问题是,会话存储中设置了太多的 Next-auth 会话 cookie(此处为 7)。 error

这是我的授权选项:

import { PrismaAdapter } from "@next-auth/prisma-adapter";
import { AuthOptions } from "next-auth";
import prisma from '@/libs/prismadb';
import bcrypt from "bcrypt";
import  CredentialsProvider  from 'next-auth/providers/credentials';

export const authOptions:AuthOptions = {
    adapter: PrismaAdapter(prisma),
    providers: [
        CredentialsProvider({
            name: 'credentials',
            credentials:{
                email: { label: 'email', type: 'text' },
                password: { label: 'password', type: 'text'},
            },
            async authorize(credentials) {

                if (!credentials?.email || !credentials.password) {
                    throw new Error(`Invalid credentials`)
                }

                const user = await prisma.user.findUnique({
                    where: {
                        email: credentials.email
                    }
                });
                if (!user || !user.hashedPassword) {
                    throw new Error(`Invalid credentials`);
                }

                const isCorrectPassword = await bcrypt.compare(credentials.password, user.hashedPassword);

                if (!isCorrectPassword) {
                    throw new Error(`Incorrect password`)
                }

                return user;

            }
        })
    ],
    debug: process.env.NODE_ENV === 'development',
    session: {
        strategy: 'jwt'
    },
    secret: process.env.NEXTAUTH_SECRET
}

我的 Next-Auth 文件夹路径是:

src/app/api/auth/[...nextauth]/route.ts

route.ts 包括:

import NextAuth from 'next-auth/next';
import { authOptions } from '@/utils/authOptions';


const handler = NextAuth(authOptions);

export { handler as GET, handler as POST };

我该如何解决这个问题?或者有什么好的资源可以使用我的外部快递服务器进行身份验证吗?

我尝试重建应用程序并在将 nextJs 应用程序升级到最新版本后放弃所有更改。

authentication next.js cookies session-cookies next-auth
1个回答
0
投票

一种解决方法是使用 回调

简短回答: 仅保存会话中所需的内容以避免出现此警告。

我与您分享一个例子。 这款没有 prisma 适配器,但逻辑类似,请参考。

在此示例中,登录端点响应对象包括

  • id
  • 访问令牌
  • 刷新令牌
  • id令牌

当我们考虑代币大小时,收到此警告是完全正常的。为了解决这个问题,我们只保存会话中需要的内容。为此,我们添加两个回调方法,如下所示。

callbacks: {
    async jwt({ token, user, account }) {
        // I advise you to log those variables here to see what you get
        if (account && user) {
            token.id = user.id
            token.accessToken = user.accessToken
            token.refreshToken = user.refreshToken

            // idToken may include some user information such as email, I leave this piece of code as an example to understand how we can extract information from it
            const decodedIdToken = JSON.parse(Buffer.from(user.idToken.split(".")[1], "base64").toString())

            if (decodedIdToken) {
                token.email = decodedIdToken["email"]
            }
        }

        const { refreshToken, ...rest } = token // we do not return refreshToken here because it would increase the session cookie size
        return rest
    },
    async session({ session, token }) {
        return {
            ...session,
            user: {
                ...session.user,
                id: token.id as string,
                email: token.email as string,
                accessToken: token.accessToken as string,
            },
            error: "" // long story, I will not go into the details about this now
        }
    }
}

当然,为了防止打字稿抱怨,我们需要在路径 /types 下添加 next-auth.d.ts 文件(types 文件夹位于项目的根目录)

import { DefaultSession } from "next-auth"

declare module "next-auth" {
    interface User {
        id: string
        email: string
        accessToken: string
        refreshToken: string
        idToken: string
    }

    interface Session {
        user: User & DefaultSession["user"]
        expires: string
        error: string
    }
}

如您所见,我们可以提取我们需要的任何信息。在此示例中,我们从会话 cookie 中排除了刷新令牌。有人可能会问“那么,一旦我的accessToken过期,我如何访问我的refreshToken?我们在会话中没有它”。答案是使用 cookies

成功登录后,我们可以将refreshToken保存为http only cookie

async authorize(credentials) {
    const payload = {
        email: credentials.email,
        password: credentials.password,
    }
    const res = await fetch(`${process.env.API_BASE_URL}/auth/login`, {
        method: "POST",
        headers: {
            "Content-Type": "application/json",
            "Access-Control-Allow-Origin": "*",
        },
        body: JSON.stringify(payload)
    })

    const user = await res.json()

    if (!res.ok) {
        throw new Error(user.message)
    }

    if (res.ok && user) {
        cookies().set({
            name: `refresh-token`,
            value: user.refreshToken,
            httpOnly: true,
            sameSite: "strict",
            secure: true,
        } as any);

        return user;
    }
    
    return null;
}
© www.soinside.com 2019 - 2024. All rights reserved.