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