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

KeystoneJS 6后台登录页添加忘记密码功能的最优实现咨询

KeystoneJS 6 密码重置功能最优实现方案

核心思路:自定义Auth页面而非修改依赖文件

直接修改node_modules内的文件会在依赖更新时被覆盖,最优方案是利用Keystone 6提供的自定义Auth页面能力,实现「忘记密码」按钮和完整重置流程,同时兼容内置的邮件发送和密码重置逻辑。


步骤1:创建自定义登录页面(含「忘记密码」按钮)

新建custom-signin.jsx文件,继承默认登录页面并添加模式切换逻辑:

import { useState } from 'react';
import { SigninPage, Button, Field, Label, Input, Alert } from '@keystone-6/auth/pages';
import { gql, useMutation } from '@keystone-6/core/admin-ui/apollo';

// 调用Keystone内置的发送重置链接mutation
const FORGOT_PASSWORD_MUTATION = gql`
  mutation ForgotPassword($email: String!) {
    sendPasswordResetLink(email: $email) {
      code
      message
    }
  }
`;

export default function CustomSigninPage(props) {
  const [mode, setMode] = useState('signin');
  const [email, setEmail] = useState('');
  const [error, setError] = useState('');
  const [success, setSuccess] = useState('');
  const [sendResetLink] = useMutation(FORGOT_PASSWORD_MUTATION);

  // 处理忘记密码表单提交
  const handleForgotPasswordSubmit = async (e) => {
    e.preventDefault();
    setError('');
    setSuccess('');
    try {
      const { data } = await sendResetLink({ variables: { email } });
      if (data.sendPasswordResetLink.code === 'SUCCESS') {
        setSuccess('重置链接已发送到你的邮箱,请查收');
      } else {
        setError(data.sendPasswordResetLink.message);
      }
    } catch (err) {
      setError('发送重置链接失败,请稍后重试');
    }
  };

  // 忘记密码模式下的页面
  if (mode === 'forgot password') {
    return (
      <div style={{ maxWidth: '400px', margin: '2rem auto', padding: '0 1rem' }}>
        <h2>忘记密码</h2>
        {error && <Alert tone="negative">{error}</Alert>}
        {success && <Alert tone="positive">{success}</Alert>}
        <form onSubmit={handleForgotPasswordSubmit}>
          <Field label="邮箱">
            <Label htmlFor="email">邮箱地址</Label>
            <Input
              id="email"
              type="email"
              value={email}
              onChange={(e) => setEmail(e.target.value)}
              required
            />
          </Field>
          <div style={{ marginTop: '1rem', display: 'flex', gap: '1rem' }}>
            <Button type="submit" tone="active">发送重置链接</Button>
            <Button onClick={() => setMode('signin')} weight="none">返回登录</Button>
          </div>
        </form>
      </div>
    );
  }

  // 默认登录页面,添加「忘记密码」按钮
  return (
    <SigninPage {...props}>
      {({ Form }) => (
        <>
          <Form />
          <Button
            weight="none"
            tone="active"
            onClick={() => setMode('forgot password')}
            style={{ marginTop: '1rem', border: 'none', background: 'transparent', cursor: 'pointer' }}
          >
            忘记密码?
          </Button>
        </>
      )}
    </SigninPage>
  );
}

步骤2:在Keystone配置中替换默认登录页面

修改keystone.ts,在auth配置里指定自定义登录页面,同时确保邮件配置正确:

import { config } from '@keystone-6/core';
import { statelessSessions } from '@keystone-6/core/session';
import { createAuth } from '@keystone-6/auth';
import CustomSigninPage from './custom-signin';

const { withAuth } = createAuth({
  listKey: 'User',
  identityField: 'email',
  secretField: 'password',
  sessionData: 'name email',
  initFirstItem: {
    fields: ['name', 'email', 'password'],
  },
  // 替换默认登录页面
  pages: {
    signin: CustomSigninPage,
  },
});

export default withAuth(
  config({
    server: {
      // 确保邮件传输配置正确(你已完成这一步,可根据实际情况调整)
      email: {
        transport: {
          host: 'smtp.example.com',
          port: 587,
          auth: {
            user: 'your-email@example.com',
            pass: 'your-email-password',
          },
        },
        from: 'your-email@example.com',
      },
    },
    lists: {
      User: {
        fields: {
          name: { type: 'text', validation: { isRequired: true } },
          email: { type: 'text', isIndexed: 'unique', validation: { isRequired: true } },
          password: { type: 'password', validation: { isRequired: true } },
        },
      },
    },
    session: statelessSessions({
      secret: '--your-secure-session-secret--',
    }),
  })
);

步骤3:(可选)自定义重置密码页面

如果需要修改默认的重置密码页面样式,可创建custom-reset-password.jsx并在auth配置中指定:

import { ResetPasswordPage } from '@keystone-6/auth/pages';

export default function CustomResetPasswordPage(props) {
  return (
    <div style={{ maxWidth: '400px', margin: '2rem auto', padding: '0 1rem' }}>
      <h2>重置你的密码</h2>
      <ResetPasswordPage.Form {...props} />
    </div>
  );
}

然后更新auth的pages配置:

pages: {
  signin: CustomSigninPage,
  resetPassword: CustomResetPasswordPage,
},

为什么这是最优方案

  • 无依赖侵入:不修改node_modules内文件,避免依赖更新导致代码丢失
  • 完全自定义:可根据需求调整UI样式、错误提示等细节
  • 兼容内置逻辑:利用Keystone提供的sendPasswordResetLink mutation和邮件发送能力,无需从零实现重置流程
  • 官方支持:自定义Auth页面是Keystone 6的官方推荐方式,保证版本兼容性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 23:53:24