Browse Source
* temp save * rebase master * fix same error * Add a new user and different permissions * fix eol-last * add Secured decorator * fix list redirect bug (#507) * Mobile menu (#463) * Increase the sliding menu * Add a simple animation * update mobile menu * update * update * update * rebase master * recovery import/first * fix error * Fix some bugs Change "ALL" to "NONE" Remove the "!" Support After landing successfully reload Reset the format * Pump your public logic * add some test * Add documents * use default currentRole in Authorized/AuthorizedRoute * rename props & change some authority setting * A big change 😄 unified router and Secured parameters 😭 loginOut logout also changed to reload * fix siderMeun bugs * Decoupled SiderMenu * Remove the handsome head of information * Add a simple error * rebase masterpull/576/head
committed by
GitHub
21 changed files with 473 additions and 99 deletions
@ -0,0 +1,16 @@ |
|||||
|
import React from 'react'; |
||||
|
import CheckPermissions from './CheckPermissions'; |
||||
|
|
||||
|
class Authorized extends React.Component { |
||||
|
render() { |
||||
|
const { children, authority, noMatch = null } = this.props; |
||||
|
const childrenRender = typeof children === 'undefined' ? null : children; |
||||
|
return CheckPermissions( |
||||
|
authority, |
||||
|
childrenRender, |
||||
|
noMatch |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export default Authorized; |
||||
@ -0,0 +1,23 @@ |
|||||
|
import React from 'react'; |
||||
|
import { Route, Redirect } from 'dva/router'; |
||||
|
import Authorized from './Authorized'; |
||||
|
|
||||
|
class AuthorizedRoute extends React.Component { |
||||
|
render() { |
||||
|
const { component: Component, render, authority, |
||||
|
redirectPath, ...rest } = this.props; |
||||
|
return ( |
||||
|
<Authorized |
||||
|
authority={authority} |
||||
|
noMatch={<Route {...rest} render={() => <Redirect to={{ pathname: redirectPath }} />} />} |
||||
|
> |
||||
|
<Route |
||||
|
{...rest} |
||||
|
render={props => (Component ? <Component {...props} /> : render(props))} |
||||
|
/> |
||||
|
</Authorized> |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export default AuthorizedRoute; |
||||
@ -0,0 +1,62 @@ |
|||||
|
import React from 'react'; |
||||
|
import PromiseRender from './PromiseRender'; |
||||
|
import { CURRENT } from './index'; |
||||
|
/** |
||||
|
* 通用权限检查方法 |
||||
|
* Common check permissions method |
||||
|
* @param { 权限判定 Permission judgment type string |array | Promise | Function } authority |
||||
|
* @param { 你的权限 Your permission description type:string} currentAuthority |
||||
|
* @param { 通过的组件 Passing components } target |
||||
|
* @param { 未通过的组件 no pass components } Exception |
||||
|
*/ |
||||
|
const checkPermissions = (authority, currentAuthority, target, Exception) => { |
||||
|
// 没有判定权限.默认查看所有
|
||||
|
// Retirement authority, return target;
|
||||
|
if (!authority) { |
||||
|
return target; |
||||
|
} |
||||
|
// 数组处理
|
||||
|
if (authority.constructor.name === 'Array') { |
||||
|
if (authority.includes(currentAuthority)) { |
||||
|
return target; |
||||
|
} |
||||
|
return Exception; |
||||
|
} |
||||
|
|
||||
|
// string 处理
|
||||
|
if (authority.constructor.name === 'String') { |
||||
|
if (authority === currentAuthority) { |
||||
|
return target; |
||||
|
} |
||||
|
return Exception; |
||||
|
} |
||||
|
|
||||
|
// Promise 处理
|
||||
|
if (authority.constructor.name === 'Promise') { |
||||
|
return () => ( |
||||
|
<PromiseRender ok={target} error={Exception} promise={authority} /> |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
// Function 处理
|
||||
|
if (authority.constructor.name === 'Function') { |
||||
|
try { |
||||
|
const bool = authority(); |
||||
|
if (bool) { |
||||
|
return target; |
||||
|
} |
||||
|
return Exception; |
||||
|
} catch (error) { |
||||
|
throw error; |
||||
|
} |
||||
|
} |
||||
|
throw new Error('unsupported parameters'); |
||||
|
}; |
||||
|
|
||||
|
export { checkPermissions }; |
||||
|
|
||||
|
const check = (authority, target, Exception) => { |
||||
|
return checkPermissions(authority, CURRENT, target, Exception); |
||||
|
}; |
||||
|
|
||||
|
export default check; |
||||
@ -0,0 +1,42 @@ |
|||||
|
import { checkPermissions } from './CheckPermissions.js'; |
||||
|
|
||||
|
const target = 'ok'; |
||||
|
const error = 'error'; |
||||
|
|
||||
|
describe('test CheckPermissions', () => { |
||||
|
it('Correct string permission authentication', () => { |
||||
|
expect(checkPermissions('user', 'user', target, error)).toEqual('ok'); |
||||
|
}); |
||||
|
it('Correct string permission authentication', () => { |
||||
|
expect(checkPermissions('user', 'NULL', target, error)).toEqual('error'); |
||||
|
}); |
||||
|
it('authority is undefined , return ok', () => { |
||||
|
expect(checkPermissions(null, 'NULL', target, error)).toEqual('ok'); |
||||
|
}); |
||||
|
it('Wrong string permission authentication', () => { |
||||
|
expect(checkPermissions('admin', 'user', target, error)).toEqual('error'); |
||||
|
}); |
||||
|
it('Correct Array permission authentication', () => { |
||||
|
expect(checkPermissions(['user', 'admin'], 'user', target, error)).toEqual( |
||||
|
'ok' |
||||
|
); |
||||
|
}); |
||||
|
it('Wrong Array permission authentication,currentAuthority error', () => { |
||||
|
expect( |
||||
|
checkPermissions(['user', 'admin'], 'user,admin', target, error) |
||||
|
).toEqual('error'); |
||||
|
}); |
||||
|
it('Wrong Array permission authentication', () => { |
||||
|
expect(checkPermissions(['user', 'admin'], 'guest', target, error)).toEqual( |
||||
|
'error' |
||||
|
); |
||||
|
}); |
||||
|
it('Wrong Function permission authentication', () => { |
||||
|
expect(checkPermissions(() => false, 'guest', target, error)).toEqual( |
||||
|
'error' |
||||
|
); |
||||
|
}); |
||||
|
it('Correct Function permission authentication', () => { |
||||
|
expect(checkPermissions(() => true, 'guest', target, error)).toEqual('ok'); |
||||
|
}); |
||||
|
}); |
||||
@ -0,0 +1,39 @@ |
|||||
|
import React from 'react'; |
||||
|
import { Spin } from 'antd'; |
||||
|
|
||||
|
export default class PromiseRender extends React.PureComponent { |
||||
|
state = { |
||||
|
component: false, |
||||
|
}; |
||||
|
async componentDidMount() { |
||||
|
this.props.promise |
||||
|
.then(() => { |
||||
|
this.setState({ |
||||
|
component: this.props.ok, |
||||
|
}); |
||||
|
}) |
||||
|
.catch(() => { |
||||
|
this.setState({ |
||||
|
component: this.props.error, |
||||
|
}); |
||||
|
}); |
||||
|
} |
||||
|
render() { |
||||
|
const C = this.state.component; |
||||
|
return C ? ( |
||||
|
<C {...this.props} /> |
||||
|
) : ( |
||||
|
<div |
||||
|
style={{ |
||||
|
width: '100%', |
||||
|
height: '100%', |
||||
|
margin: 'auto', |
||||
|
paddingTop: 50, |
||||
|
textAlign: 'center', |
||||
|
}} |
||||
|
> |
||||
|
<Spin size="large" /> |
||||
|
</div> |
||||
|
); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,49 @@ |
|||||
|
import React from 'react'; |
||||
|
import Exception from '../Exception/index'; |
||||
|
import CheckPermissions from './CheckPermissions'; |
||||
|
/** |
||||
|
* 默认不能访问任何页面 |
||||
|
* default is "NULL" |
||||
|
*/ |
||||
|
const Exception403 = () => ( |
||||
|
<Exception type="403" style={{ minHeight: 500, height: '80%' }} /> |
||||
|
); |
||||
|
|
||||
|
/** |
||||
|
* 用于判断是否拥有权限访问此view权限 |
||||
|
* authority 支持传入 string ,funtion:()=>boolean|Promise |
||||
|
* e.g. 'user' 只有user用户能访问 |
||||
|
* e.g. 'user,admin' user和 admin 都能访问 |
||||
|
* e.g. ()=>boolean 返回true能访问,返回false不能访问 |
||||
|
* e.g. Promise then 能访问 catch不能访问 |
||||
|
* e.g. authority support incoming string, funtion: () => boolean | Promise |
||||
|
* e.g. 'user' only user user can access |
||||
|
* e.g. 'user, admin' user and admin can access |
||||
|
* e.g. () => boolean true to be able to visit, return false can not be accessed |
||||
|
* e.g. Promise then can not access the visit to catch |
||||
|
* @param {string | function | Promise} authority |
||||
|
* @param {ReactNode} error 非必需参数 |
||||
|
*/ |
||||
|
const authorize = (authority, error) => { |
||||
|
/** |
||||
|
* conversion into a class |
||||
|
* 防止传入字符串时找不到staticContext造成报错 |
||||
|
* String parameters can cause staticContext not found error |
||||
|
*/ |
||||
|
let classError = false; |
||||
|
if (error) { |
||||
|
classError = () => error; |
||||
|
} |
||||
|
if (!authority) { |
||||
|
throw new Error('authority is required'); |
||||
|
} |
||||
|
return function decideAuthority(targer) { |
||||
|
return CheckPermissions( |
||||
|
authority, |
||||
|
targer, |
||||
|
classError || Exception403 |
||||
|
); |
||||
|
}; |
||||
|
}; |
||||
|
|
||||
|
export default authorize; |
||||
@ -0,0 +1,32 @@ |
|||||
|
import Authorized from './Authorized'; |
||||
|
import AuthorizedRoute from './AuthorizedRoute'; |
||||
|
import Secured from './Secured'; |
||||
|
import check from './CheckPermissions.js'; |
||||
|
|
||||
|
/* eslint-disable import/no-mutable-exports */ |
||||
|
let CURRENT = 'NULL'; |
||||
|
|
||||
|
Authorized.Secured = Secured; |
||||
|
Authorized.AuthorizedRoute = AuthorizedRoute; |
||||
|
Authorized.check = check; |
||||
|
|
||||
|
/** |
||||
|
* use authority or getAuthority |
||||
|
* @param {string|()=>String} currentAuthority |
||||
|
*/ |
||||
|
const renderAuthorize = (currentAuthority) => { |
||||
|
if (currentAuthority) { |
||||
|
if (currentAuthority.constructor.name === 'Function') { |
||||
|
CURRENT = currentAuthority(); |
||||
|
} |
||||
|
if (currentAuthority.constructor.name === 'String') { |
||||
|
CURRENT = currentAuthority; |
||||
|
} |
||||
|
} else { |
||||
|
CURRENT = 'NULL'; |
||||
|
} |
||||
|
return Authorized; |
||||
|
}; |
||||
|
|
||||
|
export { CURRENT }; |
||||
|
export default renderAuthorize; |
||||
@ -0,0 +1,5 @@ |
|||||
|
import RenderAuthorized from '../components/Authorized'; |
||||
|
import { getAuthority } from './authority'; |
||||
|
|
||||
|
const Authorized = RenderAuthorized(getAuthority()); |
||||
|
export default Authorized; |
||||
@ -0,0 +1,8 @@ |
|||||
|
// use localStorage to store the authority info, which might be sent from server in actual project.
|
||||
|
export function getAuthority() { |
||||
|
return localStorage.getItem('antd-pro-authority') || 'guest'; |
||||
|
} |
||||
|
|
||||
|
export function setAuthority(authority) { |
||||
|
return localStorage.setItem('antd-pro-authority', authority); |
||||
|
} |
||||
Loading…
Reference in new issue