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

如何防止Next-Auth自定义verify/error页面被直接访问?

解决Next-Auth邮箱认证中限制verify/error页面访问的问题

核心问题

当前直接访问/auth/verify或/auth/error页面时能正常加载,需要限制这些页面仅在通过signIn()触发的认证流程中才可访问。

方案一:利用状态标记+页面校验

步骤1:发起登录时添加自定义状态参数

在首页触发signIn的代码中,添加自定义state参数标记流程合法性:

// 首页登录按钮的点击逻辑
const handleSignIn = async (email: string) => {
  await signIn('email', {
    email,
    callbackUrl: '/dashboard',
    state: 'email-signin-initiated' // 自定义状态标记
  })
}

步骤2:在Verify页面校验状态并拦截非法访问

修改pages/auth/verify.tsx,通过useRouter获取URL中的state参数,结合useSession判断是否来自合法流程,非法访问则重定向到首页:

import { Fragment, useEffect } from 'react';
import { Box, Flex, Heading, Text } from '@chakra-ui/react';
import { CheckCircleIcon } from '@chakra-ui/icons';
import { useSession } from 'next-auth/react';
import { useRouter } from 'next/router';

export default function Verify() {
  const { status } = useSession();
  const router = useRouter();
  const { state } = router.query;

  useEffect(() => {
    // 仅当状态为未认证且带有合法state标记时,才允许停留
    if (status === 'unauthenticated' && state !== 'email-signin-initiated') {
      router.push('/');
    }
  }, [status, state, router]);

  // 加载状态下显示占位或直接重定向
  if (status === 'loading' || !state) {
    return <Flex minH={'100vh'} align={'center'} justify={'center'}>加载中...</Flex>;
  }

  return (
    <Fragment>
      <Flex minH={'100vh'} align={'center'} justify={'center'}>
        <Box textAlign="center" py={10} px={6} maxW={'500'}>
          <CheckCircleIcon boxSize={'50px'} color={'green.500'} />
          <Heading as="h2" size="xl" mt={6} mb={2}>
            检查你的邮箱
          </Heading>
          <Text color={'gray.500'}>
            验证邮件已发送至你的邮箱,请查收并点击链接完成认证。
          </Text>
        </Box>
      </Flex>
    </Fragment>
  );
}

对Error页面的同理处理

在/auth/error页面添加相同的校验逻辑,检查state参数,非法访问则重定向到首页。

方案二:将认证流程整合到登录页(无单独跳转)

如果不想单独维护verify页面,可以把整个流程放在登录页,通过组件切换实现状态展示:

// pages/index.tsx
import { useState } from 'react';
import { Box, Button, Input, Flex, Heading, Text } from '@chakra-ui/react';
import { CheckCircleIcon } from '@chakra-ui/icons';
import { signIn } from 'next-auth/react';

export default function Home() {
  const [email, setEmail] = useState('');
  const [showVerifyPrompt, setShowVerifyPrompt] = useState(false);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    await signIn('email', {
      email,
      callbackUrl: '/dashboard'
    });
    setShowVerifyPrompt(true);
  };

  if (showVerifyPrompt) {
    return (
      <Flex minH={'100vh'} align={'center'} justify={'center'}>
        <Box textAlign="center" py={10} px={6} maxW={'500'}>
          <CheckCircleIcon boxSize={'50px'} color={'green.500'} />
          <Heading as="h2" size="xl" mt={6} mb={2}>
            检查你的邮箱
          </Heading>
          <Text color={'gray.500'}>
            验证邮件已发送至你的邮箱,请查收并点击链接完成认证。
          </Text>
        </Box>
      </Flex>
    );
  }

  return (
    <Flex minH={'100vh'} align={'center'} justify={'center'}>
      <Box textAlign="center" py={10} px={6} maxW={'500'} borderWidth={1} borderRadius="lg">
        <Heading as="h2" size="xl" mt={6} mb={2}>
          登录
        </Heading>
        <form onSubmit={handleSubmit}>
          <Input
            placeholder="输入你的邮箱"
            value={email}
            onChange={(e) => setEmail(e.target.value)}
            mb={4}
            type="email"
            required
          />
          <Button type="submit" colorScheme="blue" width="full">
            发送验证邮件
          </Button>
        </form>
      </Box>
    </Flex>
  );
}

这种方式不存在单独的verify页面,自然避免了直接访问的问题,适合流程简单的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 10:20:26