发布于 2026-01-06 0 阅读
0

使用 Clerk Organizations 在 Next.js App Router 中实现基于角色的访问控制 DEV 的全球展示挑战赛,由 Mux 呈现:展示你的项目!

使用 Clerk Organizations 在 Next.js 应用路由中实现基于角色的访问控制

由 Mux 赞助的 DEV 全球展示挑战赛:展示你的项目!

介绍

在瞬息万变的 Web 开发领域,保护用户数据并控制对各种应用程序功能的访问至关重要。基于角色的访问控制 (RBAC) 已成为一种广受欢迎且行之有效的 Web 应用程序权限控制方法。RBAC 允许开发人员通过为用户分配特定角色并根据这些角色定义其访问权限,从而设计定制化且安全的用户体验。本文将探讨如何使用 Clerk(一个用于用户管理和身份验证的前沿平台)在 Next.js 应用路由中实现 RBAC。

我们将探讨Clerk如何利用组织功能简化用户身份验证和角色分配,从而简化 RBAC 与 Next.js 应用程序的集成。遵循本指南,开发人员将能够构建优先考虑安全性并根据每个用户分配的角色提供个性化体验的 Web 应用程序。

先决条件

在使用 Next.js 和 Clerk 在应用程序中实现基于角色的访问控制之前,请确保已满足以下先决条件:

  1. 网页开发基础知识(HTML、CSS 和 JavaScript)。
  2. 对 React/Next.js 有基本的了解。
  3. 必须安装Node.js和npm。
  4. 代码编辑器(Visual Studio Code)。
  5. Git 用于版本控制 - 可选。
  6. 需要注册Clerk.com账号进行身份验证。

满足这些前提条件后,您就可以使用 Clerk 在 Next.js 应用程序中实现基于角色的访问控制。如果您尚未满足任何要求,请在继续学习本教程之前,先花时间满足这些要求。

GitHub 代码库和在线演示

您可以在 GitHub 上访问该应用程序的源代码,网址为https://github.com/musebe/nextjs-clerk-organizations-rbac-authentication

要查看已完成的应用程序的实际运行情况,请访问https://nextjs-clerk-organizations-rbac-authentication.vercel.app

设立文员及文员组织

使用 Clerk 的第一步是创建 Clerk 帐户。您可以访问clerk.com并创建一个免费帐户。登录后,系统会提示您在帐户内创建一个新应用程序。此应用程序将作为您探索和使用 Clerk 各项功能和特性的起点,这些功能和特性如下所示。

职员仪表盘

登录后,点击“添加应用”按钮。给你的应用命名,并选择你希望用户使用的所有“社交认证”方式。

应用

创建职员组织

现在,是时候创建组织了。在 Clerk 中,组织相当于共享账户,使成员能够跨共享资源进行协作。组织内部,拥有更高权限的成员负责管理对组织数据和资源的访问权限。这些特权成员有权授予或撤销权限,从而确保无缝协作并安全地控制组织的资产。

登录 Clerk 并进入主页仪表盘后,要创建组织,请按照以下步骤操作:

  1. 点击“创建组织”按钮,将出现一个新的表单或模态框,提示您提供组织所需的必要信息。

  2. 请填写组织机构的必要详细信息,例如组织机构名称、标志以及任何其他相关信息。

  3. 点击按钮Create完成组织创建的的最后步骤。

  4. 然后,Clerk 将创建该组织,您将被重定向到新创建的组织的仪表板。

组织仪表盘

向组织添加成员

要向书记员组织添加成员,请按以下步骤操作:

  1. 导航至该Members部分:在 Clerk 的仪表板中选择组织后,导航至“成员”部分,用户管理在此处进行。

  2. 点击Add Members:在“成员”部分找到“添加成员”按钮,然后点击它以开始添加过程。

  3. 点击“添加成员”后,屏幕上会弹出一个窗口,提供一个表单供您输入必要的详细信息。

  4. 搜索用户:在弹出的表单中,您可以搜索要添加到组织的特定用户。在搜索字段中输入他们的电子邮件地址或用户名。

  5. 选择角色:您可以为添加的每个用户分配组织内的角色。Clerk 通常提供两种角色:admin管理员和高级管理员basic_member。请根据用户的访问级别和权限选择合适的角色。

  • 管理员 - 此admin角色授予对所有组织资源的完全访问权限。拥有管理员角色的成员享有管理员权限,可以全面管理组织及其成员关系。
    • 基本成员 - 此basic_member角色是组织用户的默认角色。他们对组织资源的访问权限受到限制。基本成员无法管理组织或组织成员关系,但可以查看有关组织及其成员的信息。
    • 点击Add:确认详细信息后,点击“添加”或“确认”按钮,完成将用户及其指定角色添加到组织的操作。

添加成员

恭喜!您已成功在 Clerk 中创建组织。您可以通过组织控制面板管理用户、角色以及与该组织相关的其他资源。

Next.js 设置

现在到了有趣的部分!让我们创建一个新的 Next.js 项目,开始实现基于角色的访问控制 (RBAC)。为此,只需导航到您选择的目录,然后在终端或命令提示符中运行以下命令:



npx create-next-app my-rbac-app


Enter fullscreen mode Exit fullscreen mode

替换my-rbac-app为您所需的项目名称。此命令将为您创建一个新的 Next.js 项目,其中包含构建支持 RBAC 的 Web 应用程序所需的所有配置。

最棒的是,从 Next.js 13 版本开始,Tailwind CSS 已默认预配置,省去了单独安装的麻烦。Next.js 和 Tailwind CSS 准备就绪后,您现在可以专注于使用 Clerk 将基于角色的访问控制 (RBAC) 集成到您新创建的 Next.js 项目中。那么,让我们开始吧,使用个性化的用户访问权限来保护您的 Web 应用程序!

将 Clerk 与 Next.js 集成

创建 Next.js 项目并配置好 Tailwind CSS 之后,下一步是将 Clerk 集成到您的应用程序中,以处理用户身份验证和基于角色的访问控制。请按照以下步骤操作:

  1. 安装 Clerk SDK:使用 npm 或 yarn 将 Clerk SDK 安装到您的 Next.js 项目中。Clerk SDK 提供必要的工具来验证用户身份和管理角色。在项目根目录下运行以下命令:


npm install @clerk/nextjs


Enter fullscreen mode Exit fullscreen mode
  1. 在 Next.js 应用中初始化 Clerk:将 Clerk SDK 导入到您的 Next.js 应用中,并使用您的 Clerk API 凭据进行初始化。此步骤使您的应用能够与 Clerk 的身份验证服务进行交互。在 Next.js 13 中,使用应用路由时,初始化操作在layout.js如下所示的文件中完成:


// app/layout.js
import '@styles/globals.css';
import { ClerkProvider } from '@clerk/nextjs';


export const metadata = {
  title: 'Clerk-Organizations',
  description: 'Clerk Role-Based Authentication Using Organizations',
};

export default function RootLayout({ children }) {
  return (
    <ClerkProvider>
      <html lang='en'>
        <body>
          <div className='main'>
            <div className='gradient' />
          </div>
          <main className='app'>
            {children}
          </main>
        </body>
      </html>
    </ClerkProvider>
  );
}



Enter fullscreen mode Exit fullscreen mode
  1. 获取 Clerk API 凭证:要初始化 Clerk SDK,您需要特定于您的 Clerk 组织的 API 凭证。从 Clerk 控制面板左侧边栏的“API 凭证”选项卡下检索这些凭证。复制这些密钥并将其粘贴到我们将要创建的文件API Keys中。.env

API密钥

  1. 在 Next.js 项目的根目录下,创建一个名为 `.js` 的新文件.env.local。创建完成后,将之前从 Clerk 控制面板复制的 ` Clerk_config`CLERK_PUBLISHABLE_KEY和 ` Clerk_config` 环境变量粘贴到此文件中。将这些密钥存储在`.js` 文件中,可以确保 Next.js 应用程序在运行时安全地访问您的敏感凭据,防止它们在代码库中泄露。请记住,为了维护环境变量的机密性,不要共享此文件或将其提交到版本控制系统中。CLERK_SECRET_KEY.env.local.env.local.env.local


NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY="<Your Publishable Key>"
CLERK_SECRET_KEY="<Your Clerk Secret Key>"


Enter fullscreen mode Exit fullscreen mode

完成上述设置和配置后,现在可以开始在项目中建立应用程序布局了。

应用程序布局

下一步是创建应用程序布局和页面。我们将使用 Next.js 13 提供的基于文件夹的方法来组织页面。在目录下app,我们将创建三个独立的文件夹,分别命名为 `<username>` Profile、 `<username>`、`<username>`UsersAdmin`<username>`,每个文件夹包含一个page.jsx文件。这些文件将作为各个页面的组件。在 `<username>`Profile页面中,我们将为用户提供个性化信息和管理账户的选项。` Users<username>` 页面将显示与用户相关的常规数据和交互。最后,`<username>` 页面Admin将作为管理员的仪表板,允许他们访问和控制应用程序的各个方面。这种组织结构将提高代码的可维护性,并使我们的 Next.js 应用程序在功能不断增长时更容易扩展。

在目录内app,为每个页面创建三个单独的文件夹:Profile,,UsersAdmin。在每个文件夹中,创建一个page.jsx文件,其中包含每个页面的内容。

你的目录结构应该如下所示:



- your-nextjs-app
  - app
    - profile
      - page.jsx
    - users
      - page.jsx
    - admin
      - page.jsx



Enter fullscreen mode Exit fullscreen mode

现在,让我们相应地更新每个文件的内容page.jsx

  1. Profile/page.jsx


const Profile = () => {
  return (
    <div>
      <h1>Welcome to the Profile Page!</h1>
      {/* Add any content or components specific to the Profile page here */}
    </div>
  );
};

export default Profile;



Enter fullscreen mode Exit fullscreen mode
  1. Users/page.jsx


const Users = () => {
  return (
    <div>
      <h1>Welcome to the Users Page!</h1>
      {/* Add any content or components specific to the Users page here */}
    </div>
  );
};

export default Users;



Enter fullscreen mode Exit fullscreen mode
  1. Admin/page.jsx


const Admin = () => {
  return (
    <div>
      <h1>Welcome to the Admin Page!</h1>
      {/* Add any content or components specific to the Admin page here */}
    </div>
  );
};

export default Admin;



Enter fullscreen mode Exit fullscreen mode

现在,可以通过以下网址访问这些页面:

  • 轮廓:http://localhost:3000/profile
  • 用户:http://localhost:3000/users
  • 行政:http://localhost:3000/admin

这种有条理的方法将确保关注点清晰分离,使管理和扩展 Next.js 应用程序变得更加容易。

导航栏

接下来是导航栏!首先,components在 Next.js 应用的根目录下创建一个文件夹。在这个新文件夹里,我们将创建一个名为 `.navbar` 的文件,Navbar.jsx用于存放我们的导航栏组件。这一步有助于我们更高效地组织和管理可复用的组件。

完成此步骤后,文件夹结构将如下所示:



- your-nextjs-app
  - components
    - Navbar.jsx
  - app
    - Profile
      - page.jsx
    - Users
      - page.jsx
    - Admin
      - page.jsx
  - pages
    ... other pages if any ...



Enter fullscreen mode Exit fullscreen mode

文件夹创建完成后components,将以下内容粘贴到文件夹Navbar.jsx内的新文件中components



import Link from 'next/link';

const Navbar = () => {
  const links = [
    { title: 'Profile', url: '/profile' },
    { title: 'Dashboard', url: '/user' },
    { title: 'Admin Dashboard', url: '/admin', role: 'admin' },
    // Add more placeholder links as needed
  ];

  return (
    <header className='text-gray-600 body-font bg-white shadow'>
      <div className='container mx-auto flex flex-wrap p-5 flex-col md:flex-row items-center justify-between'>
        <div className='flex items-center'>
          <a
            href='/'
            className='flex title-font font-medium items-center text-gray-900'
          >
            <svg
              xmlns='http://www.w3.org/2000/svg'
              fill='none'
              stroke='currentColor'
              strokeLinecap='round'
              strokeLinejoin='round'
              strokeWidth='2'
              className='w-10 h-10 text-white p-2 bg-indigo-500 rounded-full'
              viewBox='0 0 24 24'
            >
              <path d='M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5'></path>
            </svg>
            <span className='ml-3 text-xl'>SecureClerk</span>
          </a>
        </div>
        <nav className='md:ml-auto md:mr-auto flex flex-wrap items-center text-base justify-center'>
          <Link href='/profile'>
            <div className='mr-5 cursor-pointer hover:text-gray-900'>
              Profile
            </div>
          </Link>
          <Link href='/user'>
            <div className='mr-5 cursor-pointer hover:text-gray-900'>
              Dashboard
            </div>
          </Link>
          <Link href='/admin'>
            <div className='mr-5 cursor-pointer hover:text-gray-900'>
              Admin Dashboard
            </div>
          </Link>
          {/* Add more links directly here as needed */}
        </nav>
        <div className='md:flex items-center'>
          <a href='/sign-in'>
            <button className='text-white bg-indigo-500 border-0 py-2 px-4 focus:outline-none hover:bg-indigo-600 rounded text-base mr-4'>
              Login
            </button>
          </a>
          <a href='/sign-up'>
            <button className='text-white bg-indigo-500 border-0 py-2 px-4 focus:outline-none hover:bg-indigo-600 rounded text-base'>
              Sign Up
            </button>
          </a>
        </div>
      </div>
    </header>
  );
};

export default Navbar;



Enter fullscreen mode Exit fullscreen mode

下一步是修改Layout.js文件,将组件包含在内,Navbar以便整个应用程序都可以使用它。我们将Navbar组件导入到Layout.js文件中,并在布局结构中渲染它。这样,该组件Navbar就会出现在所有包含在 `<div>` 标签内的页面中RootLayout

这是更新后的Layout.js文件:



// app/Layout.js
import '@styles/globals.css';
import { ClerkProvider } from '@clerk/nextjs';
import Navbar from '../components/Navbar'; // Import the Navbar component

export const metadata = {
  title: 'Clerk-Organizations',
  description: 'Clerk Role-Based Authentication Using Organizations',
};

export default function RootLayout({ children }) {
  return (
    <ClerkProvider>
      <html lang='en'>
        <body>
          <div className='main'>
            <div className='gradient' />
          </div>
          <main className='app'>
            <Navbar /> {/* Include the Navbar component here */}
            {children}
          </main>
        </body>
      </html>
    </ClerkProvider>
  );
}



Enter fullscreen mode Exit fullscreen mode

有了这些,导航栏组件就为我们的 Next.js 应用提供了一个用户友好的导航界面。它包含“个人资料”、“仪表盘”和“管理仪表盘”的链接,点击后即可在客户端无缝导航到相应的页面。

登录和注册组件

Clerk 提供了一系列预构建组件,可将登录、注册和其他用户管理功能无缝集成到您的 Next.js 应用程序中。要使用这些功能,您可以结合使用 `<username>`<SignIn /><SignUp />`<username>` 组件以及 Next.js 的可选通配符路由。

要实现这一点,请在项目的“app”文件夹中创建两个名为“sign-up”和“sign-in”的新目录。在每个目录中,按照以下结构放置注册和登录功能的相应代码:sign-up/[[...sign-up]]/page.jsx

下面列出了使用 Clerk 组件实现的登录和注册组件的代码@clerk/nextjs

登录组件:



// app/sign-in/[[...sign-in]]/page.tsx
import { SignIn } from '@clerk/nextjs';

const SignInPage = () => {
  return (
    <div>
      <h1>Sign In</h1>
      <SignIn />
    </div>
  );
};

export default SignInPage;



Enter fullscreen mode Exit fullscreen mode

注册组件:



// app/sign-up/[[...sign-up]]/page.tsx
import { SignUp } from '@clerk/nextjs';

const SignUpPage = () => {
  return (
    <div>
      <h1>Sign Up</h1>
      <SignUp />
    </div>
  );
};

export default SignUpPage;



Enter fullscreen mode Exit fullscreen mode

添加这两个页面后,更新后的项目目录结构将如下所示:



- your-nextjs-app
  - components
    - Navbar.jsx
  - app
    - Profile
      - page.jsx
    - Users
      - page.jsx
    - Admin
      - page.jsx
    - sign-up
      - [[...sign-up]]
        - page.tsx
    - sign-in
      - [[...sign-in]]
        - page.tsx
  - pages
    ... other pages if any ...



Enter fullscreen mode Exit fullscreen mode

设置完成后,当您访问该路线时http://localhost:3000/sign-in,您将能够加载 Clerk 的登录页面,如下所示:

应用

保护您的应用程序路由

现在 Clerk 已经安装并挂载到您的应用程序中,是时候决定哪些页面是公开的,哪些页面需要身份验证了。我们可以通过middleware.js在项目根目录下的一个名为 `.clerk.conf` 的文件中声明公共路由和私有路由来实现这一点。在我们的场景中,我们只希望首页对公众可见,而页面的其余部分在用户登录应用程序之前保持隐藏状态。以下代码可以实现这一点:



import { authMiddleware } from '@clerk/nextjs';

export default authMiddleware({
  publicRoutes: ["/"]
});

export const config = {
  matcher: ['/((?!.*\\..*|_next).*)', '/', '/(api|trpc)(.*)'],
};



Enter fullscreen mode Exit fullscreen mode

英雄组件

为了最终确定布局,我们来美化一下首页,添加一些内容。首先,我们Hero.jsx在文件夹中创建一个页面components,然后将其嵌入到目录page.jsx下的文件中app

该组件将作为首页的醒目位置。



// components/Hero.jsx
const Hero = () => {
  return (
    <div className="hero">
      {/* Your hero content and layout here */}
      <h1>Welcome to Our Website</h1>
      <p>Discover amazing things with us!</p>
    </div>
  );
};

export default Hero;



Enter fullscreen mode Exit fullscreen mode

接下来,找到目录page.jsx下的文件app,并更新该文件以包含该Hero组件:



// app/page.jsx
import { Hero } from "@components";

export default function Home() {
  return (
    <main className='overflow-hidden'>
      <Hero />
      {/* Other content and components for the Home page can be added here */}
    </main>
  );
}



Enter fullscreen mode Exit fullscreen mode

现在,Hero组件已嵌入页面Home,首页顶部会显示一个精美的首页横幅区域。您可以Home根据需要向页面添加其他内容和组件,进一步优化布局。这将为您的 Next.js 应用创建一个引人入胜、赏心悦目的首页。

到目前为止,你的最终项目结构应该如下所示:



- your-nextjs-app
  - components
    - Hero.jsx
    - Navbar.jsx
  - app
    - profile
      - page.jsx
    - users
      - page.jsx
    - admin
      - page.jsx
    - sign-up
      - [[...sign-up]]
        - page.tsx
    - sign-in
      - [[...sign-in]]
        - page.jsx
    - layout.jsx
    - page.jsx
  - styles
    - globals.css
  - node_modules
  - public
    - favicon.ico
    ... other public files ...
  - package.json
  - next.config.js



Enter fullscreen mode Exit fullscreen mode

导航栏链接条件渲染

为了实现条件链接渲染,我们将使用 Clerk 的 `<Navbar>` SignedOut、 `<Navbar> UserButton` 和SignedIn`<Navbar>` 组件。当用户未登录时,我们将仅显示“登录”和“注册”按钮。但是,一旦用户登录,我们将显示导航链接以及 Clerk 的 `<Navbar>`UserButton组件,从而实现注销功能。这种方法使我们能够根据用户的身份验证状态动态调整导航栏中显示的内容。

为了实现此功能,请在 Navbar 组件中从 Clerk 的 Next.js 库导入以下组件:



import { SignedOut, UserButton, SignedIn } from '@clerk/nextjs';


Enter fullscreen mode Exit fullscreen mode

这些组件允许您根据用户的身份验证状态有条件地呈现内容,从而在导航栏中为已登录用户和未登录用户显示不同的元素。

登录后,需要验证用户的角色,区分“管理员”和“普通会员”,并据此仅向“普通会员”显示“个人资料”和“仪表盘”链接,而向“管理员”显示所有链接。我们可以使用 Clerk 的useSession钩子来获取此信息,该钩子允许访问会话状态。为此,只需将useSession钩子包含在您之前导入的 Clerk 对象中即可。这样,您就可以从会话数据中获取用户的角色,并根据条件在导航栏中呈现相应的链接。



import { SignedOut, UserButton, SignedIn, useSession } from '@clerk/nextjs';


Enter fullscreen mode Exit fullscreen mode

为了简化角色检查过程,我们创建一个实用函数,该函数将遍历会话数据并返回用户的角色。为此,请utils在项目根目录创建一个名为 `<role_name>` 的新文件夹,并userUtils.js在其中添加一个名为 `<role_name>` 的文件。在`<role_name>` 文件中userUtils.js,实现以下函数:



function checkUserRole(session) {
  if (
    !session ||
    !session.user ||
    !session.user.organizationMemberships ||
    session.user.organizationMemberships.length === 0
  ) {
    return null; // Return null if the user is not a basic member
  }

  const organizationMemberships = session.user.organizationMemberships;

  // Loop through all organization memberships
  for (const membership of organizationMemberships) {
    if (membership.role) {
      return membership.role.toLowerCase(); // Return the role in lowercase if it exists
    }
  }

  return null; // Return null if no role is found in the memberships
}

export { checkUserRole };



Enter fullscreen mode Exit fullscreen mode

此功能允许我们从会话数据中提取和确定用户的角色,从而更容易在应用程序中处理基于角色的操作。

下一步是将该checkUserRole函数从userUtils.js文件中导出,以便在组件中使用它Navbar。为此,请在Navbar组件中使用以下导入语句:



import { checkUserRole } from '../utils/userUtils';


Enter fullscreen mode Exit fullscreen mode

在组件内部Navbar,我们可以根据会话数据确定用户的角色,如下所示:



const { session } = useSession();
const userRole = checkUserRole(session);


Enter fullscreen mode Exit fullscreen mode

通过使用useSessionClerk 的钩子函数,我们可以获取用户的会话数据。然后,我们调用checkUserRole带有session参数的函数,从而获取用户的角色。这样,我们就可以在Navbar组件中高效地检查用户的角色,并根据角色信息有条件地渲染相应的链接。

用户登录后,我们可以利用这些userRole信息来确定应该向管理员和普通会员显示哪些链接。



<SignedIn>
  {links.map((link) =>
    (link.role === 'admin' && userRole === 'admin') || !link.role ? (
      <Link key={link.title} href={link.url}>
        {/* Use a div instead of an anchor tag */}
        <div className='mr-5 cursor-pointer hover:text-gray-900'>
          {link.title}
        </div>
      </Link>
    ) : null
  )}
</SignedIn>


Enter fullscreen mode Exit fullscreen mode

当用户登录后,该SignedIn组件允许我们根据用户的角色有条件地渲染导航链接。该links.map函数会遍历links数组,并对每个链接检查其是否面向管理员(link.role === 'admin')以及用户是否实际拥有“管理员”角色(userRole === 'admin')。如果两个条件都满足,或者链接未分配特定角色(!link.role),则会使用 Next.js 中的组件显示该链接Link,并将其包含在一个div元素中以进行正确的样式设置。这样,我们就可以在用户登录后根据其角色选择性地显示相应的链接。

以下是您应该如何排列SignedOutUserButton组件:



{/* SignedOut Component */}
<SignedOut>
  <a href='/sign-in'>
    <button className='text-white bg-indigo-500 border-0 py-2 px-4 focus:outline-none hover:bg-indigo-600 rounded text-base mr-4'>
      Login
    </button>
  </a>
  <a href='/sign-up'>
    <button className='text-white bg-indigo-500 border-0 py-2 px-4 focus:outline-none hover:bg-indigo-600 rounded text-base'>
      Sign Up
    </button>
  </a>
</SignedOut>

{/* UserButton Component */}
<SignedIn>
  <div className='ml-4'>
    <UserButton afterSignOutUrl='/' />
  </div>
</SignedIn>


Enter fullscreen mode Exit fullscreen mode

完成所有必要步骤后,我们现在可以根据不同的场景有条件地渲染应用程序,显示不同的链接。这使我们能够根据用户的身份验证状态、角色以及登录/注销状态来定制导航栏内容。通过这种方式,应用程序可以提供流畅且个性化的导航体验。

确保管理员控制面板页面的基于角色的访问控制

目前,我们已成功Admin Dashboard对普通会员隐藏了该链接。但是,仍存在一个问题需要解决——任何用户都可以访问该/admin路由,即使他们没有相应的权限。这种行为是不理想的,需要加以纠正。接下来,我们将处理这种情况,以确保只有具有相应admin角色的用户才能访问该Admin Dashboard页面。

为了实现此功能,我们将利用useOrganizationList管理页面上的钩子。通过该useOrganizationList钩子,我们可以访问可用组织列表以及用户所属的组织成员资格。这些信息将使我们能够实施基于角色的访问控制,并确保只有授权用户才能访问管理控制面板页面。

我们必须先将useOrganizationList钩子导入到管理页面才能使用它。以下是具体操作方法:



import { useOrganizationList } from '@clerk/nextjs';


Enter fullscreen mode Exit fullscreen mode

导入useOrganizationList钩子后,您可以使用它来访问组织数据。调用钩子后,您将收到三个变量:organizationListisLoadedsetActive



const { organizationList, isLoaded, setActive } = useOrganizationList();


Enter fullscreen mode Exit fullscreen mode

organizationList将保存可用组织的列表,提供有关每个组织及其成员的重要信息。isLoaded是一个布尔值,指示组织数据是否已成功加载并可供使用。最后,setActive是一个允许您设置活动组织的函数。

下一步是等待组织数据加载完毕,并验证用户角色是否不是管理员。我们使用useEffect钩子函数来实现这一点:



useEffect(() => {
  if (isLoaded) {
    // Find the admin organization from the loaded organization list
    const adminOrganization = organizationList.find(
      (org) => org.membership.role === 'admin'
    );

    // If the user is not an admin, redirect to the homepage
    if (!adminOrganization || adminOrganization.membership.role !== 'admin') {
      router.push('/'); // Replace '/' with the homepage URL
    } else {
      // If the user is an admin, no need to wait for the organization list; render the admin page directly
      setShowLoader(false);
    }
  }
}, [isLoaded, organizationList]);


Enter fullscreen mode Exit fullscreen mode

在这个useEffect代码块中,我们使用isLoaded变量来确保组织数据已成功加载。数据加载完成后,我们在组织列表中查找角色为“admin”的组织。如果用户没有管理员角色或未找到管理员组织,我们会使用相应router.push方法将其重定向到首页。但是,如果用户确实是管理员,我们会直接渲染管理页面,并将状态设置为 truesetShowLoaderfalse表明加载过程已完成。这样,我们就实现了基于角色的访问控制,并根据用户的角色正确处理导航。

结论

通过这些步骤,我们已成功地在 Next.js 应用路由中使用 Clerk Organizations 实现了基于角色的访问控制。这展示了如何将 Clerk 的功能无缝集成到应用程序中,使整个过程简单高效。这种方法允许我们根据用户角色控制其访问权限,从而提供安全且个性化的用户体验。事实上,与 Clerk Organizations 的集成简化了基于角色的访问控制的实现,使其成为一个流畅便捷的过程。

如果您不想通过 Clerk 控制面板创建组织,Clerk 团队提供了一些组件,您可以将其直接集成到代码库中来处理组织管理。更多详情,请参阅以下文档:https://clerk.com/docs/organizations/overview。这些组件提供了一种便捷的方式来管理应用程序中的组织和成员关系,让您可以灵活地控制组织设置过程。

参考

如需更多指导和信息,请参阅以下内容:

  1. Next.js 文档:访问https://nextjs.org/docs获取 Next.js 官方文档,了解有关该框架的详细信息。

  2. Clerk 文档:访问https://clerk.com/docs查看 Clerk 的身份验证功能和集成指南,以便更好地了解其使用方法。

  3. 使用 Clerk 简化 Next.js 应用程序中的身份验证:在博客文章中查找有关在 Next.js 应用程序中设置 Clerk 身份验证的详细步骤:Dev.to 链接

文章来源:https://dev.to/musebe/implementing-role-based-access-control-in-nextjs-app-router-using-clerk-organizations-566g