router.push 函数在登录提交处理程序中不起作用

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

我正在使用 Next.js App Router 并实现了中间件来检查访问令牌是否存在。如果用户尝试在没有令牌的情况下访问根 (/) 以外的任何页面或与登录相关的页面,我会将 returnURL 添加到搜索参数中,以便他们可以在登录后重定向回该页面。但是,这方法并未按预期发挥作用。为了处理登录过程,我使用了react-hook-form以及tanstack-query的useMutation。

const returnURL = useSearchParams().get('returnURL') || '/';

//submit handler
const onSubmit: SubmitHandler<FieldValues> = () => {
  postSigninMutate(
    { username: payload.username, password: payload.password },
    {
      onSuccess: async (res) => {
        const { response } = res;
        const authorizationToken = response.headers.get('authorization-token');
        const expiresAt = response.headers.get('authorization-token-expired-at');
        const refreshToken = response.headers.get('refresh-token');

        if (authorizationToken && expiresAt && refreshToken) {
          Cookies.set('authorization-token', authorizationToken, { secure: true });
          Cookies.set('expires-at', expiresAt);
          Cookies.set('refresh-token', refreshToken, { secure: true });
        }

        router.push(returnURL);
      },
      onError: (err) => alert(err)
    }
  );
};

<form onSubmit={handleSubmit(onSubmit)} className="flex-col-start m-0 w-80 gap-6 pt-10">
...

// middleware.ts
import { NextRequest, NextResponse } from 'next/server';

export function middleware(request: NextRequest) {
  const url = request.nextUrl.pathname;
  const accessToken = request.cookies.get('authorization-token');

  console.log(accessToken ? 'yes' : 'no');
  console.log(url);

  if (url === '/') {
    const response = NextResponse.next();
    response.headers.set('X-Skip-Icons', 'true');
    return response;
  }

  if (
    accessToken &&
    (url === '/signup' ||
      url === '/login' ||
      url === '/kakaoLogin' ||
      url === '/find-password-email' ||
      url === '/find-password-question' ||
      url === '/find-password-newpassword')
  ) {
    if (request.nextUrl.searchParams.has('returnURL')) {
      return NextResponse.redirect(new URL(request.nextUrl.searchParams.get('returnURL') || '/', request.url));
    }
    console.log('here');
    return NextResponse.redirect(new URL('/', request.url));
  }

  if (
    !accessToken &&
    url !== '/signup' &&
    url !== '/login' &&
    url !== '/kakaoLogin' &&
    url !== '/find-password-email' &&
    url !== '/find-password-question' &&
    url !== '/find-password-newpassword'
  ) {
    const redirectURL = new URL('/login', request.url);
    const returnURL = request.nextUrl.pathname + request.nextUrl.search;
    redirectURL.searchParams.set('returnURL', returnURL);

    const response = NextResponse.redirect(redirectURL);
    return response;
  }

  return NextResponse.next();
}

export const config = {
  matcher: ['/((?!api|_next/static|_next/image|favicon.ico|icons/favicon.ico|icon).*)']
};

我怀疑该问题是由于页面缓存以及客户端和服务器上的 cookie 更新不匹配造成的。调用router.refresh()后,中间件触发,页面更新,但地址栏中的URL没有变化。然后我在 router.refresh() 之后添加了一个 setTimeout 来延迟 router.push(returnURL) ,虽然这个解决方案有效,但它让我怀疑这是否是正确的方法。

但是,当我按后退按钮时,我仍然可以访问登录页面,这在成功登录后不应该发生。

router.refresh();
setTimeout(() => {
  router.push(returnURL);
}, 1000);
javascript reactjs next.js
1个回答
0
投票

解决登录后

router.push()
问题:

  1. 使用
    router.replace()
    而不是
    router.push()
    来防止导航回登录页面。
router.replace(returnURL);
  1. 设置cookie后刷新页面以确保触发中间件:
await router.refresh();
router.replace(returnURL);
  1. 确保在重定向之前设置 cookie,以避免竞争情况。

  2. 中间件应正确处理身份验证:

if (!accessToken && !['/login', '/signup'].includes(url)) { const redirectURL = new URL('/login', request.url); redirectURL.searchParams.set('returnURL', request.nextUrl.pathname); return NextResponse.redirect(redirectURL); }
这应该可以解决问题。

© www.soinside.com 2019 - 2024. All rights reserved.