iis服务器助手广告广告
返回顶部
首页 > 资讯 > 前端开发 > JavaScript >React 组件权限控制的实现
  • 264
分享到

React 组件权限控制的实现

2024-04-02 19:04:59 264人浏览 泡泡鱼
摘要

目录前话正文1. 控制方式1.1 直接计算1.2 通用权限Hoc1.3 权限包裹组件2. 控制结果2.1 显隐控制2.2 自定义渲染3. 权限数据3.1 静态权限3.2 动态权限前话

前话

具备用户体系的业务系统往往需要具备权限控制的能力。前后不分离的开发模式权限控制主要由后端结合模版引擎实现,而前后分离的开发模式由前后两端协商权限配置分别进行数据权限控制和组件权限控制。

正文

权限配置格式不限,为进行后续演示本篇设定权限配置如下:

export type IAuthConfig = {
  
  keys: string[];
};

且提供一个Hook直接获取当前用户信息:

export type IUser = {
  
  authConfig: IAuthConfig;
};


export function useUser() {
  // ...略
  return user;
}

首先我们先定义一个权限Hook,内容如下:


function getAuthKeys(auth: string | string[]) {
  return Array.isArray(auth) ? auth : [auth];
}


export enum EAuthType {
  
  "some" = "some",
  
  "every" = "every",
}


export function useAuth() {
  const { authConfig } = useUser();

  // 权限标识列表
  const authKeys = useMemo(() => authConfig?.keys ?? [], [authConfig]);
  // 校验是否具备权限
  const hasAuth = useCallback(
    (auth: string | string[], type?: EAuthType) =>
      getAuthKeys(auth)[type ?? EAuthType.every]((key) =>
        authKeys.includes(key)
      ),
    [authKeys]
  );

  const ret: [typeof authKeys, typeof hasAuth] = [authKeys, hasAuth];
  return ret;
}

1. 控制方式

对于前端开发而言一般只需做组件控制,控制方式有很多种写法。

1.1 直接计算

const Cmpt: React.FC = () => {
  const [, hasAuth] = useAuth();
  // 计算是否有权限
  const authorized = useMemo(() => hasAuth("test"), [hasAuth]);

  // ...略
};

1.2 通用权限Hoc

export function withAuth<P extends Record<string, unknown> = {}>(
  auth: string | string[],
  type?: EAuthType
) {
  return function (Component: any) {
    const WrappedComponent: React.FC<P> = (props) => {
      const [, hasAuth] = useAuth();

      const instance = React.createElement(Component, {
        ...props,
      });

      // 计算是否有权限
      const authorized = hasAuth(auth, type);

      // ...略
    };

    WrappedComponent.displayName = `withAuth(${getDisplayName(Component)})`;

    return WrappedComponent;
  };
}

1.3 权限包裹组件

const AuthWrapper: React.FC<IProps> = ({ auth, type, children }) => {
  const [, hasAuth] = useAuth();
  // 计算是否有权限
  const authorized = useMemo(() => hasAuth(auth, type), [auth, type, hasAuth]);

  // ...略
};

2. 控制结果

常见控制结果为控制组件的显示或隐藏,或根据是否具备权限做组件的自定义渲染。

为方便演示后面统一使用权限包裹组件进行说明。

2.1 显隐控制

具备权限的组件直接渲染,否则返回null,即可实现显隐控制。权限包裹组件实现如下:

const AuthWrapper: React.FC<IProps> = ({ auth, type, children }) => {
  const [, hasAuth] = useAuth();
  // 计算是否有权限
  const authorized = useMemo(() => hasAuth(auth, type), [auth, type, hasAuth]);
  // 具备权限的组件直接渲染,否则返回null
  return authorized ? children : null;
};

在需要权限控制的组件外包裹权限组件即可。

const Cmpt: React.FC = () => {
  <>
    <AuthWrapper auth="test">
      <Button>Hello World</Button>
    </AuthWrapper>
  </>;
};

2.2 自定义渲染

实际业务场景中,存在需要提醒用户没有权限的情况,这时需要权限包裹组件支持自定义渲染,实现方式有多种:

  • 静态props注入
  • 动态props映射
  • render props

相比较之下render props更为自由,权限包裹组件完善后实现如下:

type IProps = {
  
  auth: string | string[];
  
  type?: EAuthType;
  
};

const AuthWrapper: React.FC<IProps> = ({ auth, type, children }) => {
  const [, hasAuth] = useAuth();
  // 计算是否有权限
  const authorized = useMemo(() => hasAuth(auth, type), [auth, type, hasAuth]);

  // 自定义渲染
  if (typeof children === "function") {
    return children(authorized);
  }

  // 显隐控制
  return authorized ? children : null;
};

这时就可以渲染提示无权限组件:

const Cmpt: React.FC = () => {
  <>
    <AuthWrapper auth="test">
      {(authorized) => <Button disabled={!authorized}>Hello World</Button>}
    </AuthWrapper>
  </>;
};

3. 权限数据

前端开发做组件控制的颗粒度取决于权限数据的类型,权限数据类型分为静态权限和动态权限。
其中静态权限一般在完成登录认证后即可一次性获取,而动态权限则在操作数据时进行权限校验。
因此不难发现静态权限往往用于控制路由、页面或者粗糙的操作权限。而动态权限则能够对动态数据进行更细粒度的操作权限控制(需后端数据权限控制能力配合)。

3.1 静态权限

如前面描述,登录认证后即可从用户信息中得到权限标识,同样前面的栗子均也为静态权限示例。

3.2 动态权限

需要动态权限校验的场景在业务系统中也较为常见,例如用户能够看到列表数据,但禁止查阅无权限的数据详情。
由此可知对于用户而言,获取的动态的列表数据需要逐一进行权限校验,这时我们对权限Hook和包裹组件进行改造,改造后代码如下:

type IAuthDynamicConfig = {
  // ...略
};


export function useAuth() {
  // ...略

  // 动态校验是否具有权限
  const dynamicAuth = useCallback(
    (auth: string | string[], type?: EAuthType, config?: IAuthDynamicConfig) =>
      // 批量异步校验权限,实现略
      append2DynamicAuthTask(auth, type, config),
    []
  );

  const ret: [typeof authKeys, typeof hasAuth, typeof dynamicAuth] = [
    authKeys,
    hasAuth,
    dynamicAuth,
  ];
  return ret;
}


const AuthWrapper: React.FC<IProps> = ({ auth, type, config, children }) => {
  const [, hasAuth, dynamicAuth] = useAuth();

  const [authorized, setAuthorized] = useState(false);

  // 计算是否有权限
  useEffect(() => {
    if (config === undefined) {
      setAuthorized(hasAuth(auth, type));
      return;
    }
    dynamicAuth(auth, type, config).then(setAuthorized);
  }, [auth, type, config, hasAuth, dynamicAuth]);

  // ...略
};

使用方式如下:

const Cmpt: React.FC = () => {
  // ...略

  <>
    {data.map((item) => (
      <div key={item.id}>
        <div>{item.title}</div>
        <div>
          <AuthWrapper
            auth="detail"
            config={{
              module: "demo",
              identify: item.id,
            }}
          >
            {(authorized) => (
              <Button disabled={!authorized} onClick={handleDetail}>
                详情
              </Button>
            )}
          </AuthWrapper>
        </div>
      </div>
    ))}
  </>;
};

到此这篇关于React 组件权限控制的实现的文章就介绍到这了,更多相关React 组件权限控制内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: React 组件权限控制的实现

本文链接: https://www.lsjlt.com/news/139013.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作