近期作了一個 spa的單獨項目中,有個需求就是但願根據登陸人來看下,這我的是否是有權限進入當前頁面。雖然服務端作了進行接口的權限,可是每個路由加載的時候,都要去請求這個接口太浪費了。javascript
登陸受權,用戶沒有登陸只能訪問登陸頁面,若是處於登陸狀態則跳轉到當前用戶的默認首頁java
路由受權,當前登陸用戶的角色,若是對一個 URL 沒有權限訪問,則會呈現403react
數據受權,當訪問一個沒有權限的API,則跳轉到 403 頁面ios
操做受權,當頁面中某個按鈕或者區域沒有權限訪問則在頁面中隱藏redux
在路由層面攔截掉,當前這我的對應路由沒有權限,面拋出 403,且原組件也不會加載,固然也不會有任何請求axios
react router4 、react-router-config、recompose、狀態數據管理庫(本文用的 rematch )、hoc(高階組件)api
router 早期版本有進入路由的鉤子函數能夠實現這一點,可是 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 返回什麼 else 返回什麼。 我在下面貼下我怎麼實現的。 routes.jsreact-router
/* 和服務端約定的數據格式:[ {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)
}
複製代碼
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
)
複製代碼
我這裏用的 業務緣由僅僅是判斷登陸失效因此和服務端約定返回失效的code碼在請求方發裏統一處理掉我這裏用的的 axios 由於有個攔截器因此在攔截器裏作了app
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>
複製代碼
因此綜上看出能夠看出核心都在高階組件,後續我會貼出項目地址, 如今先把核心方法放出來,寫的比較倉促歡迎留言指正。