Реализовать права доступа router4 с помощью перекомпоновки

JavaScript React.js Redux

задний план

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

Нужный

  • Авторизация входа, пользователь может получить доступ только к странице входа без входа в систему. Если он находится в состоянии входа в систему, он перейдет на домашнюю страницу по умолчанию текущего пользователя.

  • Авторизация маршрутизации, роль текущего пользователя, вошедшего в систему, если нет разрешения на доступ к URL-адресу, будет отображаться 403

  • Авторизация данных, при доступе к API без разрешения перейти на страницу 403

  • Авторизация операции, когда у кнопки или области на странице нет разрешения на доступ, она будет скрыта на странице

ожидать

Перехватывается на уровне роутинга, в данный момент у этого человека нет прав на соответствующий роутинг, и выкидывается 403, и оригинальный компонент не загрузится, ну и запроса естественно не будет.

Готов к работе

react router4 , react-router-config, recompose, библиотека управления данными состояния (rematch используется в этой статье), hoc (компоненты более высокого порядка)

Схема авторизации входа

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

// app.js
  <Router>
        <Switch>
          { user.userId
            ? <AuthorizedLayout routes={routes} />
            : <UnauthorizedLayout />
          }
        </Switch>
      </Router>
// AuthorizedLayout.js
<Slider routes={this.state.routes}>
            <Switch>
              <Route path='/' exact render={() => (
                <Redirect to='/Home />
              )} />
              {renderRoutes(this.state.routes)}
            </Switch>
          </Slider>
// UnauthorizedLayout .js  就是你的 login 组件

Схема авторизации маршрутизации

Используйте внутренности компонентов более высокого порядка, чтобы определить, что возвращает if, что еще возвращает. Я опубликую, как я этого добился ниже. маршруты.js

/* 和服务端约定的数据格式:[
{url: 'xxx', authuserId: [],authRoleGroup }
]
该路由对应的所有角色或者角色组
*/
import { Icon } from 'assets'
import { WithAuthRouter } from '@components'
import Home from './home'
// 这里也可以用异步加载看个人喜好
const routes = [
  { path: '/Home', /
    exact: true,
    root: true,
    icon: Icon.COLLABORATION,
    title: '主页',
    component: WithAuthRouter(Home)
  }

WithAuthRouter.js

Здесь я поместил реквизит избыточности в маршрутизацию на уровне маршрутизации. Пока компонент, обернутый измененной функцией, может получить не только информацию о маршрутизации, но и информацию о избыточности, так что нашим компонентам не нужно подключаться, чтобы наши обычные компоненты были относительно чистыми.
В то же время я кратко представлю несколько API перекомпоновки, которые я использую:
  • compose:

    Выполнить композицию функций справа налево (выход функции справа становится входом функции слева).
  • onlyUpdateForKeys:

    Укажите значение ключа обновления, иначе запрещается обновлять компонент
  • branch:

    Понять, какой компонент возвращается, как если бы еще
  • рендеркомпонент:

    Получить компонент и вернуть компонент более высокого порядка этого компонента
  • renderNothing:

    вернуть ноль
import React from 'react'
import {connect} from 'react-redux'
import { compose, onlyUpdateForKeys, branch, renderComponent } from 'recompose'
import Exception from 'ant-design-pro/lib/Exception'
// 校验路由权限组件
const isNotAuth = props => {
// route 本路由表,user 全局登录信息、menu 服务端返回的菜单列表
  const { route: { path = null }, user = {}, menu = [] } = props
  const { userId = null, roleMap = [] } = user
  if (userId && roleMap.length) {
    const result = menu.find(i => i.menuUrl === path)
    if (result) {
      return !result.userIdList.includes(userId) && !result.userIdList.filter(i => roleMap.includes(i)).length > 0
    }

    return true
  }

  return true
}

const NotFound = () => (
  <Exception type='403' actions />
)

const renderWhileIsNotAuth = branch(
  isNotAuth,
  renderComponent(NotFound)
)

const mapState = state => ({
  user: state.user,
  menu: state.menu,
  inited: state.inited
})

const getUserAndMenu = compose(
  connect(mapState),
  onlyUpdateForKeys(['user', 'menu'])
)

export default compose(
  getUserAndMenu,
  renderWhileIsNotAuth
)

Авторизация данных

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

axios.interceptors.response.use(config => {
  const { data, status } = config
  if (status && status === 200) {
    // 图片上传接口返回的是result
    const { success, response, errorResponse, result } = data
    if (success) {
      return response || result
    } else {
      message.error(errorResponse.msg)
      if (errorResponse && errorResponse.code === 9100) {
        window.location.reload()
      }
      return null
    }
  }
  return config
}, err => {
  console.log(err)
  message.error('发生了未知错误')
  Promise.reject(err)
})

Авторизация операции

Также с использованием компонентов более высокого порядка

// 鉴权组件
import { branch, renderNothing } from 'recompose'
const withAuth = branch(
  props => {
    const getAuth = () => {
      return something
    }
    return !getAuth()
  },
  renderNothing
)
export default withAuth
// 调用
const AuthBtn = Auth(Button)
<AuthBtn
      {...someProps}
        >
          xxx
        </AuthBtn>

Эпилог

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