Внешний контроль разрешений на стороне B [разрешение на ресурсы, разрешение на данные]

Архитектура внешний интерфейс
Внешний контроль разрешений на стороне B [разрешение на ресурсы, разрешение на данные]

Это 4-й день моего участия в Gengwen Challenge, смотрите подробности мероприятия:Обновить вызов

Большинство внутренних разрешений платформы фонового управления включают два метода: Разрешения на ресурсы и разрешения на данные

Объяснение: приведенный ниже код является примером работы react + ant design pro.

1. Основное введение

  • Разрешения ресурсов: Панель навигации меню, страницы и кнопки Разрешение на доступ к ресурсам.
  • Разрешения на данные: для операций с данными на странице один и тот же человек может иметь разные разрешения на операции с данными для разных данных на одной и той же странице.

Широта полномочий

  • Широта роли: в большинстве случаев: пользователь => роль => разрешение
  • Широта пользователя: Пользователь => Разрешения

Проявления

  • Базовым представлением по-прежнему является представление древовидной структуры, поскольку соответствующеекнопка страницы менюэто поток данных от ствола к узлам дерева.

2. Ввод и отображение данных разрешения

использоватьдревовидная структурадля обработки. Единственное, с чем нужно иметь дело, этоСвязь между родительскими и дочерними узламииметь дело с. Здесь, поскольку в разных компаниях или системах могут быть разные способы ввода данных для этой части, она давно не выкладывалась.


3. Блок-схема разрешений пользовательских ресурсов

image.png


4 Внешний контроль разрешений

Права доступа к внешнему интерфейсу также разделены на две части: страницу меню и кнопку. Поскольку на реализацию внешнего управления разрешениями будет влиять форма внутреннего интерфейса, но общее направление остается прежним. Он все равно будет разделен на две части.Здесь разрешение состоит в том, чтобы использовать разрешение запроса на несколько интерфейсов, разрешение страницы запроса на начальный вход, щелкнуть бизнес-страницу и запросить код ресурса соответствующей бизнес-страницы.

4.1 Разрешения меню

Контроль разрешений меню должен понимать две концепции:

  • Одна из них — видимая страница меню: левый узел dom.
  • Одна из них — доступная страница меню: маршрутизация этой части системы.

Вот что это значит:Большая часть управления доступом к меню, о котором мы говорим, связана с видимостью меню, но видимость страницы, маршрутизируемой системой, и видимость меню на странице — это две разные вещи. Предположим, что системный маршрут /path1 виден, хотя на странице, соответствующей /path1, нет меню. Мы можем напрямую ввести соответствующий путь1 в браузере, и мы по-прежнему можем получить доступ к соответствующей странице. Это потому, что мы не занимались маршрутизацией системы.

Поняв это, нам нужно рассмотреть две части, когда нам нужно сделать разрешения страницы меню, и они соответствующие.

4.1.1 Разрешение на маршрутизацию 【кодовый адрес демонстрационный адрес

Вот два подхода:

  • Во-первых, для управления конфигурацией маршрутизации, конечно, не для настройки в файле конфигурации маршрутизации. Вместо этого сделайте это в эффективной конфигурации маршрутизации.
  • Второй — вообще не делать здесь управление роутингом, а прыгать на страницу без разрешения в роуте, писать логику для проверки, есть ли текущее разрешение, а потом вручную прыгать на 403-ю страницу.

Здесь по-прежнему используется первый метод: потому что после его использования автоматически адаптируются права доступа к меню. Это спасет нас от многих вещей.

A. Файл маршрутизации, определите права доступа к странице меню. И добавить к маршрутам исключения и 404 флаг notInAut. Этот флаг указывает на то, что эти два маршрута не проходят проверку разрешений. То же самое касается /пользователя.

export default [
  // user
  {
    path: '/user',
    component: '../layouts/UserLayout',
    routes: [
      { path: '/user', redirect: '/user/login' },
      { path: '/user/login', component: './User/Login' },
      { path: '/user/register', component: './User/Register' },
      { path: '/user/register-result', component: './User/RegisterResult' },
    ],
  },
  // app
  {
    path: '/',
    component: '../layouts/BasicLayout',
    Routes: ['src/pages/Authorized'],
    authority: ['admin', 'user'],
    routes: [
      // dashboard
      { path: '/', redirect: '/list/table-list' },
      // forms
      {
        path: '/form',
        icon: 'form',
        name: 'form',
        code: 'form_menu',
        routes: [
          {
            path: '/form/basic-form',
            code: 'form_basicForm_page',
            name: 'basicform',
            component: './Forms/BasicForm',
          },
        ],
      },
      // list
      {
        path: '/list',
        icon: 'table',
        name: 'list',
        code: 'list_menu',
        routes: [
          {
            path: '/list/table-list',
            name: 'searchtable',
            code: 'list_tableList_page',
            component: './List/TableList',
          },
        ],
      },
      {
        path: '/profile',
        name: 'profile',
        icon: 'profile',
        code: 'profile_menu',
        routes: [
          // profile
          {
            path: '/profile/basic',
            name: 'basic',
            code: 'profile_basic_page',
            component: './Profile/BasicProfile',
          },
          {
            path: '/profile/advanced',
            name: 'advanced',
            code: 'profile_advanced_page',
            authority: ['admin'],
            component: './Profile/AdvancedProfile',
          },
        ],
      },
      {
        name: 'exception',
        icon: 'warning',
        notInAut: true,
        hideInMenu: true,
        path: '/exception',
        routes: [
          // exception
          {
            path: '/exception/403',
            name: 'not-permission',
            component: './Exception/403',
          },
          {
            path: '/exception/404',
            name: 'not-find',
            component: './Exception/404',
          },
          {
            path: '/exception/500',
            name: 'server-error',
            component: './Exception/500',
          },
          {
            path: '/exception/trigger',
            name: 'trigger',
            hideInMenu: true,
            component: './Exception/TriggerException',
          },
        ],
      },
      {
        notInAut: true,
        component: '404',
      },
    ],
  },
];

б. Измените файл app.js и загрузите маршрут

export const dva = {
  config: {
    onError(err) {
      err.preventDefault();
    },
  },
};

let authRoutes = null;

function ergodicRoutes(routes, authKey, authority) {
  routes.forEach(element => {
    if (element.path === authKey) {
      Object.assign(element.authority, authority || []);
    } else if (element.routes) {
      ergodicRoutes(element.routes, authKey, authority);
    }
    return element;
  });
}

function customerErgodicRoutes(routes) {
  const menuAutArray = (localStorage.getItem('routerAutArray') || '').split(',');

  routes.forEach(element => {
    // 没有path的情况下不需要走逻辑检查
    // path 为 /user 不需要走逻辑检查
    if (element.path === '/user' || !element.path) {
      return element;
    }

    // notInAut 为true的情况下不需要走逻辑检查
    if (!element.notInAut) {
      if (menuAutArray.indexOf(element.code) >= 0 || element.path === '/') {
        if (element.routes) {
          element.routes = customerErgodicRoutes(element.routes);

          element.routes = element.routes.filter(item => !item.isNeedDelete);
        }
      } else {
        element.isNeedDelete = true;
      }
    }

    /**
     * 后台接口返回子节点的情况,父节点需要溯源处理
     */
    // notInAut 为true的情况下不需要走逻辑检查
    // if (!element.notInAut) {
    //   if (element.routes) {
    //     // eslint-disable-next-line no-param-reassign
    //     element.routes = customerErgodicRoutes(element.routes);

    //     // eslint-disable-next-line no-param-reassign
    //     if (element.routes.filter(item => item.isNeedSave && !item.hideInMenu).length) {
    //       // eslint-disable-next-line no-param-reassign
    //       element.routes = element.routes.filter(item => item.isNeedSave);
    //       if (element.routes.length) {
    //         // eslint-disable-next-line no-param-reassign
    //         element.isNeedSave = true;
    //       }
    //     }
    //   } else if (menuAutArray.indexOf(element.code) >= 0) {
    //     // eslint-disable-next-line no-param-reassign
    //     element.isNeedSave = true;
    //   }
    // } else {
    //   // eslint-disable-next-line no-param-reassign
    //   element.isNeedSave = true;
    // }

    return element;
  });

  return routes;
}

export function patchRoutes(routes) {
  Object.keys(authRoutes).map(authKey =>
    ergodicRoutes(routes, authKey, authRoutes[authKey].authority),
  );

  customerErgodicRoutes(routes);

  /**
   * 后台接口返回子节点的情况,父节点需要溯源处理
   */
  window.g_routes = routes.filter(item => !item.isNeedDelete);

  /**
   * 后台接口返回子节点的情况,父节点需要溯源处理
   */
  // window.g_routes = routes.filter(item => item.isNeedSave);
}

export function render(oldRender) {
  authRoutes = '';
  oldRender();
}

C. Измените login.js, получите код в маршруте для легкого доступа и запросите разрешения.

import { routerRedux } from 'dva/router';
import { stringify } from 'qs';
import { fakeAccountLogin, getFakeCaptcha } from '@/services/api';
import { getAuthorityMenu } from '@/services/authority';
import { setAuthority } from '@/utils/authority';
import { getPageQuery } from '@/utils/utils';
import { reloadAuthorized } from '@/utils/Authorized';
import routes from '../../config/router.config';

export default {
  namespace: 'login',

  state: {
    status: undefined,
  },

  effects: {
    *login({ payload }, { call, put }) {
      const response = yield call(fakeAccountLogin, payload);
      yield put({
        type: 'changeLoginStatus',
        payload: response,
      });
      // Login successfully
      if (response.status === 'ok') {
        // 这里的数据通过接口返回菜单页面的权限是什么

        const codeArray = [];
        // eslint-disable-next-line no-inner-declarations
        function ergodicRoutes(routesParam) {
          routesParam.forEach(element => {
            if (element.code) {
              codeArray.push(element.code);
            }
            if (element.routes) {
              ergodicRoutes(element.routes);
            }
          });
        }

        ergodicRoutes(routes);
        const authMenuArray = yield call(getAuthorityMenu, codeArray.join(','));
        localStorage.setItem('routerAutArray', authMenuArray.join(','));

        reloadAuthorized();
        const urlParams = new URL(window.location.href);
        const params = getPageQuery();
        let { redirect } = params;
        if (redirect) {
          const redirectUrlParams = new URL(redirect);
          if (redirectUrlParams.origin === urlParams.origin) {
            redirect = redirect.substr(urlParams.origin.length);
            if (redirect.match(/^\/.*#/)) {
              redirect = redirect.substr(redirect.indexOf('#') + 1);
            }
          } else {
            window.location.href = redirect;
            return;
          }
        }
        // yield put(routerRedux.replace(redirect || '/'));

        // 这里之所以用页面跳转,因为路由的重新设置需要页面重新刷新才可以生效
        window.location.href = redirect || '/';
      }
    },

    *getCaptcha({ payload }, { call }) {
      yield call(getFakeCaptcha, payload);
    },

    *logout(_, { put }) {
      yield put({
        type: 'changeLoginStatus',
        payload: {
          status: false,
          currentAuthority: 'guest',
        },
      });
      reloadAuthorized();
      yield put(
        routerRedux.push({
          pathname: '/user/login',
          search: stringify({
            redirect: window.location.href,
          }),
        }),
      );
    },
  },

  reducers: {
    changeLoginStatus(state, { payload }) {
      setAuthority(payload.currentAuthority);
      return {
        ...state,
        status: payload.status,
        type: payload.type,
      };
    },
  },
};

г. Добавить услугу

import request from '@/utils/request';

// 查询菜单权限
export async function getAuthorityMenu(codes) {
  return request(`/api/authority/menu?resCodes=${codes}`);
}

// 查询页面按钮权限
export async function getAuthority(params) {
  return request(`/api/authority?codes=${params}`);
}


4.1.2 Разрешение на маршрутизацию Разрешение на просмотр меню

Ссылаясь на описанный выше метод, разрешение на видимость меню здесь не требует выполнения других операций.


4.2 Разрешения кнопок 【кодовый адрес демонстрационный адрес

Разрешения кнопок включают две части:Права доступа к ресурсама такжеразрешение на данные. Способ получения данных другой, логика кода будет немного отличаться. Ядро — это код внутри бизнес-компонента, который накапливает себя при загрузке, а затем отправляет запрос при загрузке страницы. После получения данных выполните проверку разрешений самостоятельно. Сведите к минимуму сложность кода вашей бизнес-страницы.

Введение в логику разрешений ресурсов:

  1. PageHeaderWrapperВключенные бизнес-страницы существуют с разрешениями кнопок
  2. Передача разрешений кнопкиAuthorizedButtonВключая обработку, нужно добавить код. Однако, поскольку бизнес-страница является отдельной страницей, она отправляет набор кодов текущей страницы для запроса кода разрешения, а затемAuthorizedButtonВыполнение логической оценки разрешений.
  3. такAuthorizedButtonизcomponentWillMountВ жизненном цикле накапливается код текущей бизнес-страницы. После завершения накопления пройтиPageHeaderWrapperизcomponentDidMountФункция жизненного цикла отправляет запрос на разрешение, получает код разрешения и считывает данные через общедоступную модель globalAuthority для оценки логики разрешения.
  4. Информацию о вызовах бизнес-страницы см. в файле readme. Поскольку для кода внутри всплывающего окна компонент не был загружен при отображении страницы со списком предприятий, поэтому код накапливается заранее через extendcode для запроса разрешений.

Введение разрешения данных:

  1. Если задействованы разрешения данных, непосредственно поместите соответствующие правила данных вAuthorizedButtonВыносится внутреннее суждение, и данные, которые необходимо передать, могут быть переданы напрямую через реквизиты. Поскольку правила для разрешений на данные разные, здесь нет примеров.
  2. Логика, которую необходимо отметить, заключается в том, что разрешения на ресурсы и разрешения на данные сериализуются Сначала оцениваются разрешения на ресурсы, а затем оцениваются разрешения на данные.

а. Добавьте модель государственной власти

/* eslint-disable no-unused-vars */
/* eslint-disable no-prototype-builtins */
import { getAuthority } from '@/services/authority';

export default {
  namespace: 'globalAuthority',

  state: {
    hasAuthorityCodeArray: [], // 获取当前具有权限的资源code
    pageCodeArray: [], // 用来存储当前页面存在的资源code
  },

  effects: {
    /**
     * 获取当前页面的权限控制
     */
    *getAuthorityForPage({ payload }, { put, call, select }) {
      // 这里的资源code都是自己加载的
      const pageCodeArray = yield select(state => state.globalAuthority.pageCodeArray);
      const response = yield call(getAuthority, pageCodeArray);

      if (pageCodeArray.length) {
        yield put({
          type: 'save',
          payload: {
            hasAuthorityCodeArray: response,
          },
        });
      }
    },

    *plusCode({ payload }, { put, select }) {
      // 组件累加当前页面的code,用来发送请求返回对应的权限code
      const { codeArray = [] } = payload;
      const pageCodeArray = yield select(state => state.globalAuthority.pageCodeArray);

      yield put({
        type: 'save',
        payload: {
          pageCodeArray: pageCodeArray.concat(codeArray),
        },
      });
    },

    // eslint-disable-next-line no-unused-vars
    *resetAuthorityForPage({ payload }, { put, call }) {
      yield put({
        type: 'save',
        payload: {
          hasAuthorityCodeArray: [],
          pageCodeArray: [],
        },
      });
    },
  },

  reducers: {
    save(state, { payload }) {
      return {
        ...state,
        ...payload,
      };
    },
  },
};


б) Измените файл PageHeaderWrapper [поскольку все бизнес-страницы являются дочерними узлами этого компонента]

import React, { PureComponent } from 'react';
import { FormattedMessage } from 'umi/locale';
import Link from 'umi/link';
import PageHeader from '@/components/PageHeader';
import { connect } from 'dva';
import MenuContext from '@/layouts/MenuContext';
import { Spin } from 'antd';
import GridContent from './GridContent';
import styles from './index.less';

class PageHeaderWrapper extends PureComponent {
  componentDidMount() {
    const { dispatch } = this.props;
    dispatch({
      type: 'globalAuthority/getAuthorityForPage', // 发送请求获取当前页面的权限code
    });
  }

  componentWillUnmount() {
    const { dispatch } = this.props;
    dispatch({
      type: 'globalAuthority/resetAuthorityForPage',
    });
  }

  render() {
    const { children, contentWidth, wrapperClassName, top, loading, ...restProps } = this.props;

    return (
      <Spin spinning={loading}>
        <div style={{ margin: '-24px -24px 0' }} className={wrapperClassName}>
          {top}
          <MenuContext.Consumer>
            {value => (
              <PageHeader
                wide={contentWidth === 'Fixed'}
                home={<FormattedMessage id="menu.home" defaultMessage="Home" />}
                {...value}
                key="pageheader"
                {...restProps}
                linkElement={Link}
                itemRender={item => {
                  if (item.locale) {
                    return <FormattedMessage id={item.locale} defaultMessage={item.title} />;
                  }
                  return item.title;
                }}
              />
            )}
          </MenuContext.Consumer>
          {children ? (
            <div className={styles.content}>
              <GridContent>{children}</GridContent>
            </div>
          ) : null}
        </div>
      </Spin>
    );
  }
}

export default connect(({ setting, globalAuthority, loading }) => ({
  contentWidth: setting.contentWidth,
  globalAuthority,
  loading: loading.models.globalAuthority,
}))(PageHeaderWrapper);


в. Добавьте общедоступный компонент AuthorizedButton.

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'dva';

@connect(({ globalAuthority }) => ({
  globalAuthority,
}))
class AuthorizedButton extends Component {
  static contextTypes = {
    isMobile: PropTypes.bool,
  };

  componentWillMount() {
    // extendcode 扩展表格中的code还没有出现的情况
    const {
      dispatch,
      code,
      extendCode = [],
      globalAuthority: { pageCodeArray },
    } = this.props;

    let codeArray = [];

    if (code) {
      codeArray.push(code);
    }

    if (extendCode && extendCode.length) {
      codeArray = codeArray.concat(extendCode);
    }

    // code已经存在,证明是页面数据渲染之后或者弹出框的按钮资源,不需要走dva了
    if (pageCodeArray.indexOf(code) >= 0) {
      return;
    }

    dispatch({
      type: 'globalAuthority/plusCode',
      payload: {
        codeArray,
      },
    });
  }

  checkAuthority = code => {
    const {
      globalAuthority: { hasAuthorityCodeArray },
    } = this.props;

    return hasAuthorityCodeArray.indexOf(code) >= 0; // 资源权限
  };

  render() {
    const { children, code } = this.props;

    return (
      <span style={{ display: this.checkAuthority(code) ? 'inline' : 'none' }}>{children}</span>
    );
  }
}

export default AuthorizedButton;


г. Добавьте файл readme AuthorizedButton
GitHub.com/rod Чен-кин…

4.3 Расширение разрешений кнопок - контроль разрешений ссылок 【кодовый адрес демонстрационный адрес

Справочная информация: на странице есть разрешения, которые необходимы для управления ссылкой перехода. Если у вас есть разрешение, вы можете перейти, но если у вас нет разрешения, вы не можете перейти.image.png

А. Добавьте новое состояние в общедоступную модель: codeAuthorityObject.

image.png

С помощью redux-devtool вы можете видеть, что значение состояния codeAuthorityObject: ключ:значение кода, а значение значения равно true/false. true представляет разрешение, false — отсутствие разрешения. Он в основном используется разработчиками для самостоятельной обработки.

image.png

B. Код кнопки, который необходимо контролировать, расширьте расчет кода другими способами и отправьте запрос на получение разрешения.

image.png

C. Получить данные для контроля данных

image.png


4.4 Разрешения данных кнопок

задний план

Разрешение на данные — это разрешение на операцию с данными табличного компонента внутри бизнес-компонента. Данные списка могут принадлежать к разным типам данных, поэтому они имеют разные права на операции с данными. Для пакетных операций необходимо определить, есть ли у выбранных данных разрешения на выполнение операций, а затем отобразить, можно ли выполнять пакетные операции.

image.png

Главная идея

Сцены:
Например, в списке товаров под колонкой «операция» за каждой записью товара есть три кнопки: [редактировать], [перечислить/удалить], [удалить], и для определенного пользователя он может просматривать все товары, но для некоторых брендов он может [Вкл./Выкл. с полки], но не [Редактировать], внешний интерфейс должен контролировать доступное состояние кнопок позади каждого продукта.

Например, если у пользователя А есть разрешение на редактирование определенного фрагмента бизнес-данных (id=1999), кнопка [редактировать] в этой записи видна ему (при условии, что у него сначала есть разрешение ресурса кнопки [редактировать]). , но для другой записи (id=1899) без разрешения [Редактировать] кнопка [Редактировать] на этой записи для него невидима.

Кнопка [actType] определение атрибута

К кнопке каждой операции с данными добавляется атрибут «actType», представляющий тип действия кнопки (например, редактирование, удаление, аудит и т. д.), этот атрибут возвращается интерфейсом столичного органа, а внешний интерфейс записывает этот атрибут при вызове этого интерфейса или сохраняет его в соответствующем элементе управления. Следовательно, интерфейс не может использовать значение каждого значения перечисления этого свойства, а только должен присваивать значения в соответствии с возвращаемым значением интерфейса. Заинтересованные учащиеся также могут обратиться к значению actType следующим образом: 1 Доступно для чтения, 2 Доступно для редактирования, 3 Доступно для чтения и записи, 4 Доступно для получения, 8 Доступно для доставки, 16 Доступно для доставки, 32 Доступно для просмотра, 64 Доступно для завершения

Бизнес-интерфейс возвращает поле типа разрешения [permissionType]

Для бизнес-данных с контролем разрешений интерфейс списка или интерфейс сведений вернет поле "permissionType", которое представляет тип разрешения текущего пользователя для этих бизнес-данных. Например, когда permissionType=2, это означает, что у пользователя есть [ Изменить разрешение], разрешениеType=4 означает, что у пользователя есть разрешение на получение товаров для этих бизнес-данных, разрешениеType=6 означает, что у этого пользователя есть разрешение на редактирование и отправку этой записи (6=2+4)

Как контролировать доступное состояние кнопки?

Теперь в списке три кнопки, [Редактировать], [Получить], [Готово], соответствующие им "actType" 2, 4, 64 соответственно, permissionType=3 определенного фрагмента данных, затем статус этих три кнопки Как судить, permissionType=3 можно разложить на 1+2, что означает, что у пользователя есть права "чтение" + "редактирование" для этой записи, то из трех кнопок доступна только кнопка [Редактировать] . Тогда формула суждения такова:

((data[i].permissionType & obj.actType)==obj.actType)

Front-end js обработка данных и оценка

требуется преобразование данных

  • data.toString(2): преобразовать данные в двоичную строку.
  • parseInt(permissionType,2) : преобразовать двоичную строку в двоичные данные.

модификация кода

Макет интерфейса возвращает данные

response = [{
      "type": 3,
      "name": "创建活动-10001",
      "actType": 0,
      "code": "10001"
    }, {
      "type": 3,
      "name": "编辑-10002",
      "actType": 2,
      "code": "10002"
    }, {
      "type": 3,
      "name": "配置-10005",
      "actType": 4,
      "code": "10005"
    }, {
      "type": 3,
      "name": "订阅警报-10006",
      "actType": 8,
      "code": "10006"
    }, {
      "type": 3,
      "name": "查询详情-20001",
      "actType": 16,
      "code": "20001"
    }, {
      "type": 3,
      "name": "批量操作-10007",
      "actType": 32,
      "code": "10007"
    }, {
      "type": 3,
      "name": "更多操作-10008",
      "actType": 64,
      "code": "10008"
    }]

Каждое возвращенное разрешение интерфейса будет вместе возвращать соответствующий акттип.

Модификация кода getAuthorityForPageПростая модификация, т.к. раньше возвращался массив кода, а теперь возвращается объект

   /**
     * 获取当前页面的权限控制
     */
    *getAuthorityForPage({ payload }, { put, call, select }) {
      // 这里的资源code都是自己加载的
      const pageCodeArray = yield select(state => state.globalAuthority.pageCodeArray);
      const response = yield call(getAuthority, pageCodeArray);
      const hasAuthorityCodeArray = response || [];
      const codeAuthorityObject = {};

      pageCodeArray.forEach((value, index, array) => {
        codeAuthorityObject[value] = hasAuthorityCodeArray.map(item => item.code).indexOf(value) >= 0;
      });

      // debugger
      yield put({
        type: 'save',
        payload: {
          hasAuthorityCodeArray,
          codeAuthorityObject,
        },
      });
    },

image.png

Изменить код AuthorizedButtonПовышение авторитета данных

/* eslint-disable eqeqeq */
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'dva';

@connect(({ globalAuthority }) => ({
  globalAuthority,
}))
class AuthorizedButton extends Component {
  static contextTypes = {
    isMobile: PropTypes.bool,
  };

  componentWillMount() {
    // extendcode 扩展表格中的code还没有出现的情况
    const {
      dispatch,
      code,
      extendCode = [],
      globalAuthority: { pageCodeArray },
    } = this.props;

    let codeArray = [];

    if (code) {
      codeArray.push(code);
    }

    if (extendCode && extendCode.length) {
      codeArray = codeArray.concat(extendCode);
    }

    // code已经存在,证明是页面数据渲染之后或者弹出框的按钮资源,不需要走dva了
    if (pageCodeArray.indexOf(code) >= 0) {
      return;
    }

    dispatch({
      type: 'globalAuthority/plusCode',
      payload: {
        codeArray,
      },
    });
  }

  checkAuthority = code => {
    const {
      globalAuthority: { hasAuthorityCodeArray },
    } = this.props;

    return hasAuthorityCodeArray.map(item => item.code).indexOf(code) >= 0 && this.checkDataAuthority(); // 资源权限
  };


  /**
   * 检测数据权限
   */
  checkDataAuthority = () => {
    const {
      globalAuthority: { hasAuthorityCodeArray },
      code,                                         // 当前按钮的code
      actType,                                      // 当前按钮的actType的值通过传递传入
      recordPermissionType,                         // 单条数据的数据操作权限总和
      actTypeArray
    } = this.props;

    if (recordPermissionType || actTypeArray) {     // 单条数据权限校验
      const tempCode = hasAuthorityCodeArray.filter(item => item.code === code)
      let tempActType = ''

      if (actType) {
        tempActType = actType
      } else if (tempCode.length) {
        tempActType = tempCode[0].actType
      } else {
        return true;                                // 默认返回true
      }

      if (actTypeArray) {                           // 批量操作
        return !actTypeArray.some(item => !this.checkPermissionType(item.toString(2), tempActType.toString(2)))
      }

      // 单条数据操作
      return this.checkPermissionType(recordPermissionType.toString(2), tempActType.toString(2))
    } 

    return true;                                    // 如果字段没有值的情况下,证明不需要进行数据权限
  }

  /**
   * 二进制检查当前当前数据是否具有当前权限
   * @param {*} permissionType 
   * @param {*} actType
   */
  checkPermissionType = (permissionType, actType) => 
     (parseInt(permissionType,2) & parseInt(actType,2)).toString(2) == actType
  

  render() {
    const { children, code } = this.props;

    return (
      <span style={{ display: this.checkAuthority(code) ? 'inline' : 'none' }}>{children}</span>
    );
  }
}

export default AuthorizedButton;


метод вызова

одиночная операция с данными

<AuthoriedButton code="10005" recordPermissionType={record.permissionType}>
  <a onClick={() => this.handleUpdateModalVisible(true, record)}>配置</a>
</AuthoriedButton>

Массовые операции

 <AuthoriedButton code="10007" actTypeArray={getNotDuplicateArrayById(selectedRows, 'permissionType')}>
     <Button>批量操作</Button>
 </AuthoriedButton>