在 Next.js 中使用基于角色的逻辑(买家和卖家)实现注册 API 时遇到问题

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

我正在使用 Next.js 14 和 TypeScript 开发一个项目,其中我有两个角色:买家和卖家。在注册过程中,用户需要选择自己的角色,并根据此选择将他们重定向到适当的仪表板(买方或卖方的仪表板)。然而,我在实现处理这种基于角色的逻辑的注册 API 时遇到了麻烦。

以下是设置概述:

  1. 注册流程:

    用户填写注册表单,包括电子邮件地址、全名和密码。

    提交表格后,用户选择自己是买家还是卖家。

    根据角色,用户将被重定向到相应的仪表板(/dashboard/buyer 或 /dashboard/seller)。

  2. 遇到的问题:

    用户提交表单后,API 无法正确处理基于角色的重定向。

    有时用户的角色未正确保存,或者重定向未按预期发生。

我在 Next.js 中使用服务器操作进行表单提交和身份验证,避免使用 API 路由。

这是我正在使用的代码的简化版本:

async function handleSignUp(data: FormData) {
  "use server";
  const role = data.get('role'); // buyer or seller
  const email = data.get('email');
  const password = data.get('password');
  try {
    // sign-up logic here
    if (role === 'buyer') {
      return { redirect: '/dashboard/buyer' };
    } else if (role === 'seller') {
      return { redirect: '/dashboard/seller' };
    }
  } catch (error) {
    console.error('Sign-up error:', error);
  }
}

我尝试过的:

  • 调试表单数据,确保角色传递正确。

  • 检查表单提交后的重定向逻辑。

  • 使用服务器操作替代 API 路由。

问题:

  1. 如何在 Next.js 13 中正确实现注册 API 来处理基于角色的重定向?

  2. 是否有通过服务器操作在 Next.js 中管理基于角色的身份验证和重定向的最佳实践?

任何建议或例子将不胜感激!

javascript next.js next-auth rbac
1个回答
0
投票

假设您在用户注册时将用户详细信息(包括角色)保存在表中,并且使用

next-auth
进行身份验证,则可以在注册成功后立即触发
next-auth
登录功能。以下是带有
CredentialsProvider
的示例。

提供的中间件示例还将处理授权逻辑。根据您的要求定制

从服务器端或中间件处理基于角色的身份验证总是更好。

//下一个身份验证route.ts文件CredentialsProvider

CredentialsProvider({
      //@ts-expect-error
      async authorize(credentials, _req) {
         //@ts-expect-error
        const user: User = await getUser(credentials.email) // write your function to get user details including password, role from db;
        // do user  not exist check and other checks here
        // validate password 
        const isValid = await verifyPassword(
          //@ts-expect-error
          credentials.password,
          user.password
        );
        if (!isValid) {
          throw Error("Wrong Password");
        }
        //here instead of image, I am returning user role
        return {
          image: user.role,
          email: user.email,
          name: user.name,
        };
      },
    }),

// middleware.tsx(在项目根目录下创建此文件)

import { NextFetchEvent, NextRequest, NextResponse } from "next/server";
import { getToken } from "next-auth/jwt";
import { withAuth } from "next-auth/middleware";
export default async function middleware(
  req: NextRequest,
  event: NextFetchEvent
) {
  const PUBLIC_FILE = /\.(.*)$/;
  const pathname = req.nextUrl.pathname;
  const token = await getToken({ req });
  const isAuthenticated = !!token;
  // token will have 3 keys: name, picture ("image" which we set on CredentialsProvider),email 
  if(isAuthenticated && pathname=="/dashboard"){
      if(token.picture=="buyer"){
          return NextResponse.redirect(new URL("/dashboard/buyer", req.url));
      }else if(token.picture=="seller"){
          return NextResponse.redirect(new URL("/dashboard/seller", req.url));
      }
  }

 // Allow users to access URLs on following conditions, edit as per the requirement
 if (
    pathname.startsWith("/_next") ||
    pathname. Includes("/api") ||
    pathname. Includes("/signup") 
    PUBLIC_FILE.test(pathname) ||
    isAuthenticated
  ) {
    return NextResponse.next();
  }
  // apart from above conditions if user is not authenticated, it will redirect to /login route
  const authMiddleware = withAuth({
    pages: {
      signIn: "/login",
    },
  });
  // @ts-expect-error
  return authMiddleware(req, event);
}

//登录功能

import { signIn } from "next-auth/react";
//after successful signup
 const result = await signIn("credentials", {
      redirect: false,
      email: "email",
      password:"password",
    });
    setLoading(false);
    if (result && !result. Error) {
       //success scenario, this is just a dummy route, middleware will redirect this as per the role
      router.replace("/dashboard");
    } else if (result?.error) {
      //failed scenario
    }
© www.soinside.com 2019 - 2024. All rights reserved.