You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NextAuth「记住我」功能实现问题及配置咨询

NextAuth 「记住我」功能实现方案及问题解决

一、JWT过期时间不生效的原因及修复

你当前配置里的jwt.maxAge是NextAuth旧版本的写法,在v5版本中,JWT的有效期配置已经合并到session选项里了,所以之前的设置不会生效。

修复方法:把jwt配置替换为session配置:

// auth.config.ts
export const authConfig = {
  pages: {
    signIn: '/login',
    signOut: '/'
  }, 
  // 替换原来的jwt配置为session
  session: {
    strategy: "jwt", // 明确指定JWT策略
    maxAge: 60 * 60 * 1, // 默认1小时有效期
    updateAge: 60 * 60 * 0.5, // 每30分钟自动刷新JWT
  },
  callbacks: {
    authorized({ auth, request: { nextUrl } }) {
      const isLoggedIn = !!auth?.user;
      const isOnDashboard = nextUrl.pathname.startsWith('/dashboard');
      const isOnSettings = nextUrl.pathname.startsWith('/settings')
      if (isOnDashboard || isOnSettings) {
        if (isLoggedIn) return true;
        return false; // 未登录用户重定向到登录页
      } else if (isLoggedIn) {
        return Response.redirect(new URL('/dashboard', nextUrl));
      }
      return true;
    },
  },
  providers: [], 
} satisfies NextAuthConfig;

二、「记住我」功能的正确实现思路

先纠正一个误区:不要把JWT存储到localStorage,localStorage容易遭受XSS攻击窃取令牌,NextAuth默认使用HttpOnly Cookie存储JWT,安全性更高。要实现「关闭网站自动删除」的效果,只需要配置Cookie为会话级Cookie(不设置expires,浏览器关闭时自动清除),而「记住我」则使用持久化Cookie(设置较长的expires)。

核心逻辑:

  • 用户勾选「记住我」时,设置Cookie有效期为7天(或自定义时长)
  • 用户不勾选时,使用会话级Cookie,浏览器关闭后自动失效

三、具体实现步骤

1. 在登录页面添加「记住我」复选框

假设你的登录页面是React组件,添加复选框并传递remember参数到signIn方法:

// app/login/page.tsx
'use client';
import { signIn } from '@/app/auth';
import { useState } from 'react';

export default function LoginPage() {
  const [rememberMe, setRememberMe] = useState(false);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    const formData = new FormData(e.currentTarget);
    await signIn('credentials', {
      email: formData.get('email') as string,
      password: formData.get('password') as string,
      remember: rememberMe, // 传递记住我状态
      redirect: true,
    });
  };

  return (
    <form onSubmit={handleSubmit}>
      <input type="email" name="email" required placeholder="邮箱" />
      <input type="password" name="password" required placeholder="密码" />
      <label>
        <input
          type="checkbox"
          checked={rememberMe}
          onChange={(e) => setRememberMe(e.target.checked)}
        />
        记住我
      </label>
      <button type="submit">登录</button>
    </form>
  );
}

2. 动态配置Cookie及JWT有效期

在auth.ts中,通过回调和Cookie配置,根据remember参数动态调整有效期:

// auth.ts
import NextAuth from 'next-auth';
import { authConfig } from './auth.config';
import Credentials from 'next-auth/providers/credentials';
import { z } from 'zod';
import bcrypt from 'bcrypt';
import { getUser } from '@/app/libs/dbCore';

export const { auth, signIn, signOut } = NextAuth({
  ...authConfig,
  // 动态配置Cookie
  cookies: {
    sessionToken: {
      name: `next-auth.session-token`,
      options: ({ req }) => {
        // 从登录请求中获取remember状态
        const remember = req.body?.remember === 'true';
        return {
          httpOnly: true,
          sameSite: 'lax',
          path: '/',
          secure: process.env.NODE_ENV === 'production',
          // 勾选记住我则设置7天有效期,否则不设置expires(会话级)
          expires: remember ? new Date(Date.now() + 60 * 60 * 24 * 7 * 1000) : undefined,
          maxAge: remember ? 60 * 60 * 24 * 7 : undefined,
        };
      },
    },
  },
  callbacks: {
    // 在JWT中记录记住我状态
    async jwt({ token, user }) {
      if (user?.remember !== undefined) {
        token.remember = user.remember;
      }
      return token;
    },
    // 同步状态到session
    async session({ session, token }) {
      session.remember = token.remember;
      return session;
    },
  },
  providers: [
    Credentials({
      // 声明接收remember参数
      credentials: {
        email: { label: "Email", type: "email" },
        password: { label: "Password", type: "password" },
        remember: { label: "Remember Me", type: "boolean" }
      },
      async authorize(credentials) {
        const parsedCredentials = z
          .object({ 
            email: z.string().email(), 
            password: z.string().min(6),
            remember: z.boolean().optional() // 校验remember参数
          })
          .safeParse(credentials);
   
        if (parsedCredentials.success) {
          const { email, password, remember } = parsedCredentials.data;
          const user = await getUser(email);
          if (!user) return null;

          const passwordsMatch = await bcrypt.compare(password, user.password);
          if (passwordsMatch) {
            // 返回用户信息时携带remember状态
            return { ...user, remember };
          }
        }

        console.log('Invalid credentials');
        return null;
      },
    }),
  ],
  // 动态设置JWT有效期
  session: {
    strategy: "jwt",
    maxAge: ({ session }) => {
      // 勾选记住我则7天有效期,否则1小时
      return session?.remember ? 60 * 60 * 24 * 7 : 60 * 60 * 1;
    },
  },
});

四、关键注意事项

  • 安全性优先:始终使用HttpOnly Cookie存储JWT,避免localStorage带来的XSS风险。
  • 版本适配:以上配置针对NextAuth v5版本,v4版本配置项会有差异(比如v4用jwt.maxAge和cookie.expires)。
  • 测试验证:修改配置后,清除浏览器旧Cookie并重启服务器,避免旧配置干扰测试结果。

内容的提问来源于stack exchange,提问作者pish

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 11:22:09