初始化 antd-pro
This commit is contained in:
8
admin-web/src/components/Authorized/Authorized.js
Normal file
8
admin-web/src/components/Authorized/Authorized.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import CheckPermissions from './CheckPermissions';
|
||||
|
||||
const Authorized = ({ children, authority, noMatch = null }) => {
|
||||
const childrenRender = typeof children === 'undefined' ? null : children;
|
||||
return CheckPermissions(authority, childrenRender, noMatch);
|
||||
};
|
||||
|
||||
export default Authorized;
|
||||
13
admin-web/src/components/Authorized/AuthorizedRoute.d.ts
vendored
Normal file
13
admin-web/src/components/Authorized/AuthorizedRoute.d.ts
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
import * as React from 'react';
|
||||
import { RouteProps } from 'react-router';
|
||||
|
||||
type authorityFN = (currentAuthority?: string) => boolean;
|
||||
|
||||
type authority = string | string[] | authorityFN | Promise<any>;
|
||||
|
||||
export interface IAuthorizedRouteProps extends RouteProps {
|
||||
authority: authority;
|
||||
}
|
||||
export { authority };
|
||||
|
||||
export default class AuthorizedRoute extends React.Component<IAuthorizedRouteProps, any> {}
|
||||
15
admin-web/src/components/Authorized/AuthorizedRoute.js
Normal file
15
admin-web/src/components/Authorized/AuthorizedRoute.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import React from 'react';
|
||||
import { Route, Redirect } from 'react-router-dom';
|
||||
import Authorized from './Authorized';
|
||||
|
||||
// TODO: umi只会返回render和rest
|
||||
const AuthorizedRoute = ({ component: Component, render, authority, redirectPath, ...rest }) => (
|
||||
<Authorized
|
||||
authority={authority}
|
||||
noMatch={<Route {...rest} render={() => <Redirect to={{ pathname: redirectPath }} />} />}
|
||||
>
|
||||
<Route {...rest} render={props => (Component ? <Component {...props} /> : render(props))} />
|
||||
</Authorized>
|
||||
);
|
||||
|
||||
export default AuthorizedRoute;
|
||||
88
admin-web/src/components/Authorized/CheckPermissions.js
Normal file
88
admin-web/src/components/Authorized/CheckPermissions.js
Normal file
@@ -0,0 +1,88 @@
|
||||
import React from 'react';
|
||||
import PromiseRender from './PromiseRender';
|
||||
import { CURRENT } from './renderAuthorize';
|
||||
|
||||
function isPromise(obj) {
|
||||
return (
|
||||
!!obj &&
|
||||
(typeof obj === 'object' || typeof obj === 'function') &&
|
||||
typeof obj.then === 'function'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用权限检查方法
|
||||
* 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 (Array.isArray(authority)) {
|
||||
if (authority.indexOf(currentAuthority) >= 0) {
|
||||
return target;
|
||||
}
|
||||
if (Array.isArray(currentAuthority)) {
|
||||
for (let i = 0; i < currentAuthority.length; i += 1) {
|
||||
const element = currentAuthority[i];
|
||||
if (authority.indexOf(element) >= 0) {
|
||||
return target;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Exception;
|
||||
}
|
||||
|
||||
// string 处理
|
||||
if (typeof authority === 'string') {
|
||||
if (authority === currentAuthority) {
|
||||
return target;
|
||||
}
|
||||
if (Array.isArray(currentAuthority)) {
|
||||
for (let i = 0; i < currentAuthority.length; i += 1) {
|
||||
const element = currentAuthority[i];
|
||||
if (authority === element) {
|
||||
return target;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Exception;
|
||||
}
|
||||
|
||||
// Promise 处理
|
||||
if (isPromise(authority)) {
|
||||
return <PromiseRender ok={target} error={Exception} promise={authority} />;
|
||||
}
|
||||
|
||||
// Function 处理
|
||||
if (typeof authority === 'function') {
|
||||
try {
|
||||
const bool = authority(currentAuthority);
|
||||
// 函数执行后返回值是 Promise
|
||||
if (isPromise(bool)) {
|
||||
return <PromiseRender ok={target} error={Exception} promise={bool} />;
|
||||
}
|
||||
if (bool) {
|
||||
return target;
|
||||
}
|
||||
return Exception;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
throw new Error('unsupported parameters');
|
||||
};
|
||||
|
||||
export { checkPermissions };
|
||||
|
||||
const check = (authority, target, Exception) =>
|
||||
checkPermissions(authority, CURRENT, target, Exception);
|
||||
|
||||
export default check;
|
||||
55
admin-web/src/components/Authorized/CheckPermissions.test.js
Normal file
55
admin-web/src/components/Authorized/CheckPermissions.test.js
Normal file
@@ -0,0 +1,55 @@
|
||||
import { checkPermissions } from './CheckPermissions';
|
||||
|
||||
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('currentAuthority is undefined , return error', () => {
|
||||
expect(checkPermissions('admin', null, target, error)).toEqual('error');
|
||||
});
|
||||
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');
|
||||
});
|
||||
it('authority is string, currentAuthority is array, return ok', () => {
|
||||
expect(checkPermissions('user', ['user'], target, error)).toEqual('ok');
|
||||
});
|
||||
it('authority is string, currentAuthority is array, return ok', () => {
|
||||
expect(checkPermissions('user', ['user', 'admin'], target, error)).toEqual('ok');
|
||||
});
|
||||
it('authority is array, currentAuthority is array, return ok', () => {
|
||||
expect(checkPermissions(['user', 'admin'], ['user', 'admin'], target, error)).toEqual('ok');
|
||||
});
|
||||
it('Wrong Function permission authentication', () => {
|
||||
expect(checkPermissions(() => false, ['user'], target, error)).toEqual('error');
|
||||
});
|
||||
it('Correct Function permission authentication', () => {
|
||||
expect(checkPermissions(() => true, ['user'], target, error)).toEqual('ok');
|
||||
});
|
||||
it('authority is undefined , return ok', () => {
|
||||
expect(checkPermissions(null, ['user'], target, error)).toEqual('ok');
|
||||
});
|
||||
});
|
||||
65
admin-web/src/components/Authorized/PromiseRender.js
Normal file
65
admin-web/src/components/Authorized/PromiseRender.js
Normal file
@@ -0,0 +1,65 @@
|
||||
import React from 'react';
|
||||
import { Spin } from 'antd';
|
||||
|
||||
export default class PromiseRender extends React.PureComponent {
|
||||
state = {
|
||||
component: null,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.setRenderComponent(this.props);
|
||||
}
|
||||
|
||||
componentDidUpdate(nextProps) {
|
||||
// new Props enter
|
||||
this.setRenderComponent(nextProps);
|
||||
}
|
||||
|
||||
// set render Component : ok or error
|
||||
setRenderComponent(props) {
|
||||
const ok = this.checkIsInstantiation(props.ok);
|
||||
const error = this.checkIsInstantiation(props.error);
|
||||
props.promise
|
||||
.then(() => {
|
||||
this.setState({
|
||||
component: ok,
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
this.setState({
|
||||
component: error,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Determine whether the incoming component has been instantiated
|
||||
// AuthorizedRoute is already instantiated
|
||||
// Authorized render is already instantiated, children is no instantiated
|
||||
// Secured is not instantiated
|
||||
checkIsInstantiation = target => {
|
||||
if (!React.isValidElement(target)) {
|
||||
return target;
|
||||
}
|
||||
return () => target;
|
||||
};
|
||||
|
||||
render() {
|
||||
const { component: Component } = this.state;
|
||||
const { ok, error, promise, ...rest } = this.props;
|
||||
return Component ? (
|
||||
<Component {...rest} />
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
margin: 'auto',
|
||||
paddingTop: 50,
|
||||
textAlign: 'center',
|
||||
}}
|
||||
>
|
||||
<Spin size="large" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
55
admin-web/src/components/Authorized/Secured.js
Normal file
55
admin-web/src/components/Authorized/Secured.js
Normal file
@@ -0,0 +1,55 @@
|
||||
import React from 'react';
|
||||
import Exception from '../Exception';
|
||||
import CheckPermissions from './CheckPermissions';
|
||||
/**
|
||||
* 默认不能访问任何页面
|
||||
* default is "NULL"
|
||||
*/
|
||||
const Exception403 = () => <Exception type="403" />;
|
||||
|
||||
// Determine whether the incoming component has been instantiated
|
||||
// AuthorizedRoute is already instantiated
|
||||
// Authorized render is already instantiated, children is no instantiated
|
||||
// Secured is not instantiated
|
||||
const checkIsInstantiation = target => {
|
||||
if (!React.isValidElement(target)) {
|
||||
return target;
|
||||
}
|
||||
return () => target;
|
||||
};
|
||||
|
||||
/**
|
||||
* 用于判断是否拥有权限访问此view权限
|
||||
* authority 支持传入 string, function:()=>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, function: () => 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(target) {
|
||||
const component = CheckPermissions(authority, target, classError || Exception403);
|
||||
return checkIsInstantiation(component);
|
||||
};
|
||||
};
|
||||
|
||||
export default authorize;
|
||||
23
admin-web/src/components/Authorized/demo/AuthorizedArray.md
Normal file
23
admin-web/src/components/Authorized/demo/AuthorizedArray.md
Normal file
@@ -0,0 +1,23 @@
|
||||
---
|
||||
order: 1
|
||||
title:
|
||||
zh-CN: 使用数组作为参数
|
||||
en-US: Use Array as a parameter
|
||||
---
|
||||
|
||||
Use Array as a parameter
|
||||
|
||||
```jsx
|
||||
import RenderAuthorized from 'ant-design-pro/lib/Authorized';
|
||||
import { Alert } from 'antd';
|
||||
|
||||
const Authorized = RenderAuthorized('user');
|
||||
const noMatch = <Alert message="No permission." type="error" showIcon />;
|
||||
|
||||
ReactDOM.render(
|
||||
<Authorized authority={['user', 'admin']} noMatch={noMatch}>
|
||||
<Alert message="Use Array as a parameter passed!" type="success" showIcon />
|
||||
</Authorized>,
|
||||
mountNode,
|
||||
);
|
||||
```
|
||||
@@ -0,0 +1,31 @@
|
||||
---
|
||||
order: 2
|
||||
title:
|
||||
zh-CN: 使用方法作为参数
|
||||
en-US: Use function as a parameter
|
||||
---
|
||||
|
||||
Use Function as a parameter
|
||||
|
||||
```jsx
|
||||
import RenderAuthorized from 'ant-design-pro/lib/Authorized';
|
||||
import { Alert } from 'antd';
|
||||
|
||||
const Authorized = RenderAuthorized('user');
|
||||
const noMatch = <Alert message="No permission." type="error" showIcon />;
|
||||
|
||||
const havePermission = () => {
|
||||
return false;
|
||||
};
|
||||
|
||||
ReactDOM.render(
|
||||
<Authorized authority={havePermission} noMatch={noMatch}>
|
||||
<Alert
|
||||
message="Use Function as a parameter passed!"
|
||||
type="success"
|
||||
showIcon
|
||||
/>
|
||||
</Authorized>,
|
||||
mountNode,
|
||||
);
|
||||
```
|
||||
25
admin-web/src/components/Authorized/demo/basic.md
Normal file
25
admin-web/src/components/Authorized/demo/basic.md
Normal file
@@ -0,0 +1,25 @@
|
||||
---
|
||||
order: 0
|
||||
title:
|
||||
zh-CN: 基本使用
|
||||
en-US: Basic use
|
||||
---
|
||||
|
||||
Basic use
|
||||
|
||||
```jsx
|
||||
import RenderAuthorized from 'ant-design-pro/lib/Authorized';
|
||||
import { Alert } from 'antd';
|
||||
|
||||
const Authorized = RenderAuthorized('user');
|
||||
const noMatch = <Alert message="No permission." type="error" showIcon />;
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<Authorized authority="admin" noMatch={noMatch}>
|
||||
<Alert message="user Passed!" type="success" showIcon />
|
||||
</Authorized>
|
||||
</div>,
|
||||
mountNode,
|
||||
);
|
||||
```
|
||||
28
admin-web/src/components/Authorized/demo/secured.md
Normal file
28
admin-web/src/components/Authorized/demo/secured.md
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
order: 3
|
||||
title:
|
||||
zh-CN: 注解基本使用
|
||||
en-US: Basic use secured
|
||||
---
|
||||
|
||||
secured demo used
|
||||
|
||||
```jsx
|
||||
import RenderAuthorized from 'ant-design-pro/lib/Authorized';
|
||||
import { Alert } from 'antd';
|
||||
|
||||
const { Secured } = RenderAuthorized('user');
|
||||
|
||||
@Secured('admin')
|
||||
class TestSecuredString extends React.Component {
|
||||
render() {
|
||||
<Alert message="user Passed!" type="success" showIcon />;
|
||||
}
|
||||
}
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<TestSecuredString />
|
||||
</div>,
|
||||
mountNode,
|
||||
);
|
||||
```
|
||||
32
admin-web/src/components/Authorized/index.d.ts
vendored
Normal file
32
admin-web/src/components/Authorized/index.d.ts
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
import * as React from 'react';
|
||||
import AuthorizedRoute, { authority } from './AuthorizedRoute';
|
||||
export type IReactComponent<P = any> =
|
||||
| React.StatelessComponent<P>
|
||||
| React.ComponentClass<P>
|
||||
| React.ClassicComponentClass<P>;
|
||||
|
||||
type Secured = (
|
||||
authority: authority,
|
||||
error?: React.ReactNode
|
||||
) => <T extends IReactComponent>(target: T) => T;
|
||||
|
||||
type check = <T extends IReactComponent, S extends IReactComponent>(
|
||||
authority: authority,
|
||||
target: T,
|
||||
Exception: S
|
||||
) => T | S;
|
||||
|
||||
export interface IAuthorizedProps {
|
||||
authority: authority;
|
||||
noMatch?: React.ReactNode;
|
||||
}
|
||||
|
||||
export class Authorized extends React.Component<IAuthorizedProps, any> {
|
||||
public static Secured: Secured;
|
||||
public static AuthorizedRoute: typeof AuthorizedRoute;
|
||||
public static check: check;
|
||||
}
|
||||
|
||||
declare function renderAuthorize(currentAuthority: string): typeof Authorized;
|
||||
|
||||
export default renderAuthorize;
|
||||
11
admin-web/src/components/Authorized/index.js
Normal file
11
admin-web/src/components/Authorized/index.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import Authorized from './Authorized';
|
||||
import AuthorizedRoute from './AuthorizedRoute';
|
||||
import Secured from './Secured';
|
||||
import check from './CheckPermissions';
|
||||
import renderAuthorize from './renderAuthorize';
|
||||
|
||||
Authorized.Secured = Secured;
|
||||
Authorized.AuthorizedRoute = AuthorizedRoute;
|
||||
Authorized.check = check;
|
||||
|
||||
export default renderAuthorize(Authorized);
|
||||
56
admin-web/src/components/Authorized/index.md
Normal file
56
admin-web/src/components/Authorized/index.md
Normal file
@@ -0,0 +1,56 @@
|
||||
---
|
||||
title: Authorized
|
||||
subtitle: 权限
|
||||
cols: 1
|
||||
order: 15
|
||||
---
|
||||
|
||||
权限组件,通过比对现有权限与准入权限,决定相关元素的展示。
|
||||
|
||||
## API
|
||||
|
||||
### RenderAuthorized
|
||||
|
||||
`RenderAuthorized: (currentAuthority: string | () => string) => Authorized`
|
||||
|
||||
权限组件默认 export RenderAuthorized 函数,它接收当前权限作为参数,返回一个权限对象,该对象提供以下几种使用方式。
|
||||
|
||||
|
||||
### Authorized
|
||||
|
||||
最基础的权限控制。
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
|----------|------------------------------------------|-------------|-------|
|
||||
| children | 正常渲染的元素,权限判断通过时展示 | ReactNode | - |
|
||||
| authority | 准入权限/权限判断 | `string | array | Promise | (currentAuthority) => boolean | Promise` | - |
|
||||
| noMatch | 权限异常渲染元素,权限判断不通过时展示 | ReactNode | - |
|
||||
|
||||
### Authorized.AuthorizedRoute
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
|----------|------------------------------------------|-------------|-------|
|
||||
| authority | 准入权限/权限判断 | `string | array | Promise | (currentAuthority) => boolean | Promise` | - |
|
||||
| redirectPath | 权限异常时重定向的页面路由 | string | - |
|
||||
|
||||
其余参数与 `Route` 相同。
|
||||
|
||||
### Authorized.Secured
|
||||
|
||||
注解方式,`@Authorized.Secured(authority, error)`
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
|----------|------------------------------------------|-------------|-------|
|
||||
| authority | 准入权限/权限判断 | `string | Promise | (currentAuthority) => boolean | Promise` | - |
|
||||
| error | 权限异常时渲染元素 | ReactNode | <Exception type="403" /> |
|
||||
|
||||
### Authorized.check
|
||||
|
||||
函数形式的 Authorized,用于某些不能被 HOC 包裹的组件。 `Authorized.check(authority, target, Exception)`
|
||||
注意:传入一个 Promise 时,无论正确还是错误返回的都是一个 ReactClass。
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
|----------|------------------------------------------|-------------|-------|
|
||||
| authority | 准入权限/权限判断 | `string | Promise | (currentAuthority) => boolean | Promise` | - |
|
||||
| target | 权限判断通过时渲染的元素 | ReactNode | - |
|
||||
| Exception | 权限异常时渲染元素 | ReactNode | - |
|
||||
25
admin-web/src/components/Authorized/renderAuthorize.js
Normal file
25
admin-web/src/components/Authorized/renderAuthorize.js
Normal file
@@ -0,0 +1,25 @@
|
||||
/* eslint-disable import/no-mutable-exports */
|
||||
let CURRENT = 'NULL';
|
||||
/**
|
||||
* use authority or getAuthority
|
||||
* @param {string|()=>String} currentAuthority
|
||||
*/
|
||||
const renderAuthorize = Authorized => currentAuthority => {
|
||||
if (currentAuthority) {
|
||||
if (typeof currentAuthority === 'function') {
|
||||
CURRENT = currentAuthority();
|
||||
}
|
||||
if (
|
||||
Object.prototype.toString.call(currentAuthority) === '[object String]' ||
|
||||
Array.isArray(currentAuthority)
|
||||
) {
|
||||
CURRENT = currentAuthority;
|
||||
}
|
||||
} else {
|
||||
CURRENT = 'NULL';
|
||||
}
|
||||
return Authorized;
|
||||
};
|
||||
|
||||
export { CURRENT };
|
||||
export default Authorized => renderAuthorize(Authorized);
|
||||
Reference in New Issue
Block a user