当我在下一个身份验证的提供者中选择凭据时,如何同步下一个身份验证会话的过期时间和来自服务器的令牌

Rag*_*hav 18 session node.js jwt next.js next-auth

我已经为我的 Next.js 应用程序实现了 next-auth 身份验证系统。在提供程序中,我选择了凭据,因为我有一个 Node.js 后端服务器。

我面临的问题是下一个身份验证会话的到期时间与我后端的 jwt 令牌的到期时间不同步。这会导致不一致。请帮助我。

下面是我的下一个授权代码

import NextAuth, {
  NextAuthOptions,
  Session,
  SessionStrategy,
  User,
} from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import { login } from "@actions/auth";
import { toast } from "react-toastify";
import { JWT } from "next-auth/jwt";
import { NextApiRequest, NextApiResponse } from "next";
import { SessionToken } from "next-auth/core/lib/cookie";

// For more information on each option (and a full list of options) go to
// https://next-auth.js.org/configuration/options
const nextAuthOptions = (req: NextApiRequest, res: NextApiResponse) => {
  return {
    providers: [
      CredentialsProvider({
        name: "Credentials",
        credentials: {
          email: { label: "Email", type: "text" },
          password: { label: "Password", type: "password" },
        },
        async authorize(
          credentials: Record<"email" | "password", string> | undefined,
          req
        ): Promise<Omit<User, "id"> | { id?: string | undefined } | null> {
          // Add logic here to look up the user from the credentials supplied
          const response = await login(
            credentials?.email!,
            credentials?.password!
          );
          const cookies = response.headers["set-cookie"];

          res.setHeader("Set-Cookie", cookies);
          if (response) {
            var user = { token: response.data.token, data: response.data.user };
            return user;
          } else {
            return null;
          }
        },
      }),
    ],
    refetchInterval: 1 * 24 * 60 * 60,
    secret: process.env.NEXTAUTH_SECRET,
    debug: true,
    session: {
      strategy: "jwt" as SessionStrategy,
      maxAge: 3 * 24 * 60 * 60,
    },
    jwt: {
      maxAge: 3 * 24 * 60 * 60,
    },
    callbacks: {
      jwt: async ({ token, user }: { token: JWT; user?: User }) => {
        user && (token.accessToken = user.token);
        user && (token.user = user.data);
        return token;
      },
      session: async ({ session, token }: { session: Session; token: JWT }) => {
        session.user = token.user;
        session.accessToken = token.accessToken;
        return session;
      },
    },
  };
};
export default (req: NextApiRequest, res: NextApiResponse) => {
  return NextAuth(req, res, nextAuthOptions(req, res));
};
Run Code Online (Sandbox Code Playgroud)

小智 6

我有一个类似的设置:在客户端上使用带有 jwt 和单独后端会话令牌的凭证身份验证的 NextAuth(版本 4)和 Next.js(带有 App Router 的版本 13)。

这就是我们保持会话同步的方法:

  1. 正如其他人提到的,在 NextAuthOptions 中,将maxAge属性设置为与后端服务器上的令牌相同的过期时间。

    const nextAuthOptions = {
      providers: [...],
      session: {
        strategy: 'jwt',
        maxAge: 4 * 60 * 60 // 4 hours
      },
      ...
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 在经过身份验证的页面的路由树的顶层,检查您的客户端会话是否即将过期,如果是,请刷新令牌。我使用 NextAuth useSession更新函数刷新客户端上的令牌,并向后端 API 发送请求以更新服务器上的令牌过期时间。这将添加到layout.tsx顶层层次结构中的文件中,以供任何需要经过身份验证才能查看的视图。

    --layout.tsx--

    'use client';
    import { useSession } from 'next-auth/react';
    
    export default function Layout() {
      const { data: session, status, update } = useSession();
    
      useEffect(() => {
        const interval = setInterval(() => {
          update(); // extend client session
          // TODO request token refresh from server
        }, 1000 * 60 * 60)
        return () => clearInterval(interval)
      }, [update]); 
      return (
        {children}
      )
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 如果您还想添加功能来确定用户在延长会话之前是否处于空闲状态,您可以使用react-idle-timer。

    --完整的layout.tsx文件--

    'use client';
    import React, { useEffect } from 'react';
    import { useSession, signOut } from 'next-auth/react';
    import { useIdleTimer } from 'react-idle-timer';
    
    export default function Layout({ children }: { children: React.ReactNode 
    }) {
      const { data: session, status, update } = useSession();
      const CHECK_SESSION_EXP_TIME = 300000; // 5 mins
      const SESSION_IDLE_TIME = 300000; // 5 mins 
      const BASE_URL = process.env.NEXT_PUBLIC_BASE_URL;
    
      const onUserIdle = () => {
        console.log('IDLE');
      };
    
      const onUserActive = () => {
        console.log('ACTIVE');
      };
    
      const { isIdle } = useIdleTimer({
        onIdle: onUserIdle,
        onActive: onUserActive,
        timeout: SESSION_IDLE_TIME, //milliseconds
        throttle: 500
      });
    
      useEffect(() => {
        const checkUserSession = setInterval(() => {
          const expiresTimeTimestamp = Math.floor(new Date(session?.expires || '').getTime());
          const currentTimestamp = Date.now();
          const timeRemaining = expiresTimeTimestamp - currentTimestamp;
    
          // If the user session will expire before the next session check
          // and the user is not idle, then we want to refresh the session
          // on the client and request a token refresh on the backend
          if (!isIdle() && timeRemaining < CHECK_SESSION_EXP_TIME) {
            update(); // extend the client session
    
            // request refresh of backend token here
    
          } else if (timeRemaining < 0) {
            // session has expired, logout the user and display session expiration message
            signOut({ callbackUrl: BASE_URL + '/login?error=SessionExpired' });
          }
        }, CHECK_SESSION_EXP_TIME);
    
        return () => {
          clearInterval(checkUserSession);
        };
      }, [update]); 
      return (
        <main>
          {children}
        </main>
      );
    }
    
    Run Code Online (Sandbox Code Playgroud)


You*_*zef 3

在你的选择中,有一个maxAge财产。将其设置为等于您在后端服务器中设置的任何时间。时间以秒为单位,因此您当前设置为 3 天。

看这里

  • maxAge:秒 - 空闲会话到期并不再有效之前的时间。如果用户不闲着,那是行不通的。 (2认同)