基於角色的訪問控制並根據不同的場景顯示不同的反饋資訊

让速不让路發表於2024-05-14

要實現基於角色的訪問控制(RBAC),並根據不同的場景(如選單項、頁面、元件)顯示不同的反饋資訊(如隱藏、禁用、提示等),可以設計一套完整的解決方案。這個方案需要結合許可權管理、上下文、路由控制和條件渲染等多個方面。以下是一個詳細的實現方案:

1. 設定角色和許可權

首先,定義你的角色和許可權:

const roles = {
  ADMIN: 'admin',
  EDITOR: 'editor',
  VIEWER: 'viewer',
};

const permissions = {
  READ: 'read',
  WRITE: 'write',
  DELETE: 'delete',
};

const rolePermissions = {
  [roles.ADMIN]: [permissions.READ, permissions.WRITE, permissions.DELETE],
  [roles.EDITOR]: [permissions.READ, permissions.WRITE],
  [roles.VIEWER]: [permissions.READ],
};

2. 許可權上下文

建立許可權上下文,用於在整個應用中共享當前使用者的角色和許可權資訊:

import React, { createContext, useContext } from 'react';

const PermissionsContext = createContext();

export const PermissionsProvider = ({ currentUser, children }) => {
  return (
    <PermissionsContext.Provider value={currentUser}>
      {children}
    </PermissionsContext.Provider>
  );
};

export const usePermissions = () => {
  return useContext(PermissionsContext);
};

3. 建立許可權檢查函式

實現一個函式,用於檢查當前使用者是否具有特定許可權:

const hasPermission = (role, requiredPermission) => {
  const userPermissions = rolePermissions[role] || [];
  return userPermissions.includes(requiredPermission);
};

4. 建立高階元件和組合元件

實現一個高階元件(HOC)和組合元件,用於許可權控制:

高階元件(HOC)

import React from 'react';
import { usePermissions } from './PermissionsContext';

const withAuthorization = (WrappedComponent, requiredPermission) => {
  return (props) => {
    const currentUser = usePermissions();
    const userRole = currentUser.role;

    if (hasPermission(userRole, requiredPermission)) {
      return <WrappedComponent {...props} />;
    } else {
      return <div>Access Denied</div>; // 或者返回其他元件如 <Redirect />
    }
  };
};

export default withAuthorization;

組合元件

import React from 'react';
import { usePermissions } from './PermissionsContext';

const WithAuthorization = ({ requiredPermission, children, fallback }) => {
  const currentUser = usePermissions();
  const userRole = currentUser.role;

  if (hasPermission(userRole, requiredPermission)) {
    return children;
  } else {
    return fallback || <div>Access Denied</div>;
  }
};

export default WithAuthorization;

5. 路由控制

使用 ProtectedRoute 元件控制路由訪問:

import React from 'react';
import { Route, Redirect } from 'react-router-dom';
import { usePermissions } from './PermissionsContext';

const ProtectedRoute = ({ component: Component, requiredPermission, ...rest }) => {
  const currentUser = usePermissions();
  const userRole = currentUser.role;

  return (
    <Route
      {...rest}
      render={(props) =>
        hasPermission(userRole, requiredPermission) ? (
          <Component {...props} />
        ) : (
          <Redirect to="/unauthorized" /> // 或者重定向到 404 頁面
        )
      }
    />
  );
};

export default ProtectedRoute;

6. 選單控制

根據許可權動態生成選單:

import React from 'react';
import { usePermissions } from './PermissionsContext';
import { Link } from 'react-router-dom';

const Menu = () => {
  const currentUser = usePermissions();
  const userRole = currentUser.role;

  return (
    <nav>
      <ul>
        {hasPermission(userRole, permissions.READ) && (
          <li>
            <Link to="/dashboard">Dashboard</Link>
          </li>
        )}
        {hasPermission(userRole, permissions.WRITE) && (
          <li>
            <Link to="/editor">Editor</Link>
          </li>
        )}
        {hasPermission(userRole, permissions.DELETE) && (
          <li>
            <Link to="/admin">Admin</Link>
          </li>
        )}
      </ul>
    </nav>
  );
};

export default Menu;

7. 元件內許可權控制

在元件內使用組合元件進行許可權控制:

import React from 'react';
import WithAuthorization from './WithAuthorization';

const AdminComponent = () => {
  return <div>Admin Content</div>;
};

const App = () => {
  return (
    <PermissionsProvider currentUser={{ role: roles.EDITOR }}>
      <div>
        <h1>My App</h1>
        <Menu />
        <WithAuthorization requiredPermission={permissions.DELETE} fallback={<div>Access Denied</div>}>
          <AdminComponent />
        </WithAuthorization>
      </div>
    </PermissionsProvider>
  );
};

export default App;

8. 顯示不同的反饋資訊

根據不同的場景顯示不同的反饋資訊:

import React from 'react';
import WithAuthorization from './WithAuthorization';

const DisabledButton = () => <button disabled>You don't have permission</button>;

const AdminComponent = () => {
  return <div>Admin Content</div>;
};

const App = () => {
  return (
    <PermissionsProvider currentUser={{ role: roles.VIEWER }}>
      <div>
        <h1>My App</h1>
        <Menu />
        <WithAuthorization requiredPermission={permissions.DELETE} fallback={<DisabledButton />}>
          <AdminComponent />
        </WithAuthorization>
      </div>
    </PermissionsProvider>
  );
};

export default App;

總結

透過上述步驟,可以實現一套完整的基於 RBAC 的許可權控制方案,涵蓋了選單項、頁面訪問、元件顯示等不同場景的許可權控制。組合方式和高階元件(HOC)各有優勢,可以根據實際需求靈活使用。透過許可權上下文、許可權檢查函式、高階元件和組合元件,可以確保許可權控制邏輯的複用性和靈活性,使得許可權管理更加簡潔和高效。

相關文章