授權是我們應用程式中決定使用者可以在何種資源上執行哪些操作的過程,這是每個應用程式的重要要求。實施基於角色的存取控制 (RBAC) 是一個簡單的方法來管理和控制我們應用程式中的授權。

在這篇文章中,我們將討論如何在 Next.js 應用程式中以安全和可擴展的方式添加 RBAC 授權的過程。

我們將從在 Next.js 中設置一個基本的待辦事項應用程式開始,並實施 JWT 用於使用者身份驗證。接下來,我們將使用Permit.io 配置 RBAC 政策,同步我們的使用者,並將使用者的角色升級為具有全部權限的管理員。

在本教程結束時,您將清楚地了解如何使用 RBAC 保護 Next.js 應用程式,讓您完全控制每個使用者根據其角色可以訪問的內容。

讓我們開始吧!

設置基本的 Next.js 專案

為了開始,讓我們創建一個新的 Next.js 專案。為了節省時間(假設您理解 Next.js 的基本概念),我們已經設置了一個啟動專案,您將找到我們在本教程中將使用的簡單待辦事項應用程式。

  1. 確保您的電腦上已安裝 Node.js 和 npm。您可以從官方Node.js 網站下載它們。

  2. 打開終端窗口,使用以下命令創建一個新的 Next.js 專案:

git clone https://github.com/Arindam200/Permit-RBAC

這將複製一個具有默認設置的 Next.js 專案,其中包含我們將在本教程中使用的啟動代碼。

  1. 創建專案後,通過運行以下命令導航到專案目錄:
cd rbac-permit-starter-next.js
  1. 接下來,我們將通過運行以下命令安裝所需依賴項:
npm install

現在我們已成功在本地設置了 Next.js 專案,我們可以繼續實施基本的 RBAC 模型。

使用 JWT 進行使用者身份驗證

在開始授權之前,我們需要驗證使用者身份。

身份驗證階段驗證並為每個使用者提供唯一的身份,這有助於區分一個使用者與另一個使用者。授權限制使用者只能在應用程式內執行他們被授權執行的操作。

為了保持我們的應用程式簡單,我們正在使用兩個具有管理員和一般使用者權限的虛擬 JWT。相同的方法將適用於與任何提供 JWT 的身份驗證提供者的實施,例如 Clerk、Auth0 或 Kinde。

虛擬使用者詳細信息如下:

  1. 創建兩個具有以下憑據的使用者:
    • 使用者 1(管理員):
      • 密鑰:1
      • 電子郵件[email protected]
      • 名字:Project
      • 姓氏:Admin
      • 租戶:Todo-tenant(或您創建的租戶)
      • 角色:管理員
    • 使用者 2(普通使用者):
      • 密鑰:2
      • 電子郵件[email protected]
      • 名字:Project
      • 姓氏:User
      • 租戶:Todo-tenant(或您創建的租戶)
      • 角色:使用者

在您的代碼編輯器中,導航到檔案 src > data > sampleData.js 裡的代碼:

 const sampleData = [
     "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwibmFtZSI6IlByb2plY3QgQWRtaW4iLCJlbWFpbCI6ImFkbWluQGdtYWlsLmNvbSJ9.KtQpee_bZF_Sx0t87trx8-ljuE3SwJ7SZYeYzZO-694", 
  "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwibmFtZSI6IlByb2plY3QgVXNlciIsImVtYWlsIjoidXNlckBnbWFpbC5jb20ifQ.FVG2dcFVsOy1cmzImHqtbeJ0mnT1h4aCSN7aSPq9Xew",
    ];
export default sampleData;

這包含了上面寫的憑據的兩個使用者的 JWT。我們將解碼這些 JWT 以獲取使用者信息。

授權反模式

開發人員經常使用以下具體的條件語句來強制執行 RBAC 規則。

代碼片段

在這個例子中,我們有一個包含 ID 和角色屬性的使用者物件。

deleteUser 函數檢查當前使用者的角色是否為 'admin',然後才允許他刪除使用者。

updatePost 函數檢查使用者角色是否已被更新。

使用具體的 if 語句硬編碼授權規則會產生幾個問題:

  • 重複性:在函數調用中添加授權通常會導致在多個函數中重複檢查,這會使代碼混亂,並增加更新時出錯的風險。
  • 複雜性:隨著角色和權限的增加,嵌套的 if 語句變得複雜且難以維護,這使得代碼容易出錯且不易閱讀。
  • 靈活性不足:硬編碼的授權邏輯需要對於角色或權限的任何更改進行手動更新,這既耗時又容易出錯。

在本教程中,我們將使用Permit.io 實施 RBAC - 一個授權即服務提供者。Permit.io 通過提供更集中、靈活和可擴展的權限管理方法,解決了硬編碼授權的缺點。

在 Permit 中配置基本的 RBAC 政策

要開始配置權限,請登錄 app.permit.io。接下來,我們將為這個專案創建一個新的工作區。

按照以下步驟操作:

  • 在 Permit 中創建一個帳戶
  • 輸入工作區名稱
  • 提供工作區密鑰
  • 點擊 "啟動您的帳戶"

Permit 工作區

接下來,我們需要創建一個資源。資源是我們應用程式中需要保護或管理訪問的任何元素。例如,在這個應用程式中,Todo 是一個代表我們需要管理和保護的任務的資源。

讓我們創建一個名為 Todo 的資源。

  1. 轉到政策頁面並點擊創建 > 資源
  2. 創建以下資源
  3. 指定與它相關的五個動作(創建、閱讀、更新、編輯、刪除):

TODO 資源

接下來,我們將創建一個角色。角色是一種簡單的方式,可以將權限分組並分配給使用者或其他實體。

  1. 轉到政策頁面並點擊創建 > 角色
  2. 添加以下角色,並按照下面所示的動作進行設定:
    • 管理員
    • 使用者
  3. 保存這些更改。

角色

接下來,我們將轉到“政策編輯器”部分並設置政策。在設置政策之前,讓我們討論一下這些行動:

  1. 創建:向待辦事項清單中添加一個新任務。
  2. 閱讀:查看任務的詳細信息。
  3. 更新:將任務標記為已完成或未完成。
  4. 編輯:更改任務的名稱、截止日期或優先級。
  5. 刪除:從待辦事項清單中刪除任務。

我們需要更新我們的政策,以便管理員有權執行所有動作,而使用者僅能執行閱讀和更新動作。

要創建這個政策,請轉到政策編輯器,按下面顯示的方式勾選所有複選框,然後保存更改。

政策儀表板

就這樣。我們已成功設置了基於角色的存取控制 (RBAC) 模型,可以在我們的應用程式中使用。

同步使用者到 Permit

現在我們已經創建了 RBAC 配置,讓我們將虛擬使用者添加到我們的 Permit.io 目錄。由於我們使用的是虛擬 JWT,我們將手動將使用者添加到 Permit 目錄。如果您有身份驗證提供者,則可以利用 syncUser API 將所有現有使用者導入 Permit。

開始操作:

  1. 轉到 permit 目錄
  2. 選擇默認租戶
  3. 點擊添加使用者

添加使用者

  1. 根據下面顯示的內容填寫使用者詳細信息並保存:
    • 普通使用者

普通使用者

  • 管理員使用者

管理員使用者

現在我們已在 Permit 中創建了一些使用者,我們準備開始編碼。

讓我們開始添加環境變量:

  1. 轉到 設定 > API 密鑰 > 開發密鑰
  2. 複製密鑰並粘貼到 .env 中,如下所示:
PERMIT_TOKEN=”複製的 API 密鑰”

現在讓我們將應用程式與 Permit.io 連接,以實施我們已設置的政策。

為此,我們將創建一個網關,使用 API 令牌和政策決策點 (PDP) 端點初始化 Permit.io 客戶端。
這種設置允許應用程式根據預定的存取控制規則執行授權檢查。

  1. 轉到 src > lib > permitProvider.js
  2. 如下所示初始化 Permit.io 客戶端:
import { Permit } from 'permitio';
const permit = new Permit({
  // 用於與 Permit.io API 認證的令牌
  token: process.env.NEXT_PUBLIC_PERMIT_TOKEN,
  // Permit.io 用於評估政策的政策決策點 (PDP) URL
  pdp: "https://cloudpdp.api.permit.io",
});
export default permit;

現在我們已經創建了兩個使用者,是時候利用現有政策來測試我們的基於角色的存取控制 (RBAC) 模型的運作。
在我們繼續之前,讓我們討論一下檢查是如何運作以授予或限制對授權個體的存取。

我們應用程序中的授權架構

讓我們了解一下我們將如何在應用程式中實施授權:

  • 每當使用者想在前端執行操作時,前端會將 user_id 和操作名稱發送到後端 API。
  • 我們的後端將檢查使用者是否有權執行該操作。
  • 根據使用者是否被允許,後端向前端發送響應。
  • 在收到響應後,如果使用者被允許,則執行操作;否則,拒絕,並彈出通知使用者他們未被授權。

授權架構

檢查與驗證權限

現在我們已經將應用程式與 Permit.io 連接,是時候看看 Permit.io 如何管理資源。

  1. 轉到 src > api > check-permission > route.js
  2. 添加以下代碼:
import permit from "@/lib/permitProvider";

export async function GET(req) {

  const { searchParams } = new URL(req.url)
  const id = searchParams.get('id');
  const operation = searchParams.get('operation')

  try {    
    const permitted = await permit.check(String(id), String(operation), {
      type: 'TodoTasks',
      tenant: 'todo-tenant',
    });

    if (permitted) {
      return Response.json({
        success: true,
        message: "被允許"
      }, {  status: 200 })

    }

  } catch (err) {
    console.error("檢查權限時出錯:", err);
  }
  return Response.json({
            success: false,
            message: "不被允許"
          }, {  status: 403 })
}

在上述代碼中,我們提取查詢參數,使用 Permit.io 檢查權限並返回結果。

以下是逐步分析:

  1. 提取查詢參數
    • GET 函數由對該 API 路由的 HTTP GET 請求觸發。
    • 它從請求的 URL 中檢索 idoperation 參數。
  2. 使用 Permit.io 檢查權限
    • 調用 permit.check() 方法,在 todo-tenant 中檢查是否由 id 標識的使用者有權執行指定的操作(例如,創建、更新、刪除)在 TodoTasks 資源上。
  3. 返回結果
    • 成功 (200):如果使用者有必要的權限,則返回狀態碼為 200 的成功響應。
    • 未授權 (403):如果使用者沒有所需的權限,則返回狀態碼為 403 的失敗響應。

現在來看看這個集中化的函數如何進行 API 調用:

const checkPermission = async (operation) => {
    const response = await fetch(`/api/check-permission?id=${identifier}&operation=${operation}`);
    const data = await response.json();
    return data.success;
  };

它通過所需的參數 ID 和操作來響應我們設計的 API 路由。

根據角色限制對資源的訪問

我們有我們的 Todo 資源,根據其政策,具有“管理員”角色的個體可以執行所有五個動作:讀取、創建、編輯、更新和刪除。而“使用者”角色的僅能執行讀取和更新操作。

創建:確認個體是否具有 "編輯" 權限的函數,並使用新值更新指定的待辦事項。

const handleSaveEdit = async () => {
    if (!await checkPermission("edit")) {
      alert("您沒有編輯待辦事項的權限。");
      return;
    }
    const updatedTodos = todos.map((todo, i) =>
      i === editingIndex
        ? { ...todo, content: editingContent, deadline: editingDeadline, priority: editingPriority }
        : todo
    );
    setTodos(updatedTodos);
    setEditingIndex(null);
    setEditingContent("");
    setEditingDeadline("");
    setEditingPriority("low");
  };

編輯:確認個體是否具有 "編輯" 權限以更新指定的待辦事項。

const handleSaveEdit = async () => {
    if (!await checkPermission("edit")) {
      alert("您沒有編輯待辦事項的權限。");
      return;
    }

    const updatedTodos = todos.map((todo, index) =>
      index === editingIndex
        ? { ...todo, content: editingContent, deadline: editingDeadline, priority: editingPriority }
        : todo
    );
    setTodos(updatedTodos);
    setEditingIndex(null);
    setEditingContent("");
    setEditingDeadline("");
    setEditingPriority("low");
  };

更新:確認個體是否具有 "更新" 權限,切換指定待辦事項的 "完成" 狀態。

const handleToggleDone = async (index) => {
    if (!await checkPermission("update")) {
      alert("您沒有更新待辦事項的權限。");
      return;
    }
    const updatedTodos = todos.map((todo, i) =>
      i === index ? { ...todo, done: !todo.done } : todo
    );
    setTodos(updatedTodos);
  };

刪除:確認個體是否具有 "刪除" 權限,並從列表中移除指定的待辦事項。

 const handleDeleteTodo = async (index) => {
    if (!await checkPermission("delete")) {
      alert("您沒有刪除待辦事項的權限。");
      return;
    }
    const updatedTodos = todos.filter((_, i) => i !== index);
    setTodos(updatedTodos);
  };

我們已添加所有必要的操作來根據定義的角色限制個體的行為,並定義函數以創建、編輯、更新和刪除我們的 Todo 應用程式中的項目。

至此,我們的簡單 Todo 應用程式與 Next.js 和 Permit 完成了 🥳。

您可以通過運行以下命令啟動應用程式:

npm run dev

這將使我們的 Next.js 應用程式在 http://localhost:3000 上運行。

我們的 Todo 應用程式的示範

擁有使用者權限的個體示範

在這個演示中,我們將展示我們的使用者如何只能讀取待辦事項但無法編輯或刪除它們:

  • 讀取待辦事項:具有使用者角色的個體可以讀取待辦事項。
  • 無法編輯待辦事項:該使用者無法修改現有的待辦事項。
  • 無法刪除待辦事項:該使用者無權刪除待辦事項。

https://youtu.be/03kBVFMcv8A

將我們的使用者升級為管理員

要將使用者的角色從使用者改為管理員,請導航到 Permit.io 儀表板,並根據如下所示更新使用者的角色分配:

將我們的使用者升級為管理員

擁有所有權限的管理員使用者示範

更新角色為管理員之後,該使用者現在在應用程式中擁有全部權限。作為管理員,該使用者可以:

  • 更新待辦事項:修改現有的待辦事項。
  • 刪除待辦事項:從列表中移除待辦事項。
  • 讀取待辦事項:讀取現有的待辦事項。

以下視頻演示了管理員角色的增強功能:

https://youtu.be/hGlxLKmZ3qk

這就是如何輕鬆地在任何應用程式中實施 RBAC 政策,也就是使用permit.io。

我們也可以看到在 Permit.io 儀表板的審核日誌部分請求的跟蹤,如下所示:

審核日誌

結論

在本教程中,我們探討了如何設置和配置 Next.js 應用程式中的 RBAC,以根據使用者角色控制訪問。

現在您已將 RBAC 實施到您的應用程式中,您可以利用它來提高應用程式的安全性,針對應用程式中的真實用例進行應用。

如果您想要比用戶角色更細粒度的控制,但又需要用戶詳細身份,該怎麼辦?

為了獲得這些及更多,我們建議您繼續閱讀我們的學習材料,例如RBAC 與 ABAC 之間的區別以及使用 Permit.io 將 ABAC 添加到您的應用程序

想要了解更多關於實施授權的信息?有問題嗎?隨時通過我們的Slack 社區與我們聯繫。


原文出處:https://dev.to/studio1hq/how-to-add-rbac-authorization-in-nextjs-16m3

按讚的人:

共有 0 則留言