我想实现基于角色的访问控制,并希望控制应用程序的某些部分(或子部分)的显示.
我将从Node.js获取权限列表,这只是一个具有这种结构的对象:
{ users: 'read',models: 'write',... dictionaries: 'none',}@H_502_6@密钥是受保护的资源,
value是此资源的用户权限(以下之一:none,read,write).
我将它存储到redux状态.似乎很容易.
反应路由器路由onEnter / onChange挂钩或redux-auth-wrapper将检查none权限.这似乎也很容易.
但是,对任何组件视图应用读/写权限的最佳方法是什么(例如,如果用户具有{models:’read’}权限,则隐藏模型组件中的编辑按钮).
我找到了this solution并为我的任务改了一点:
class Check extends React.Component { static propTypes = { resource: React.PropTypes.string.isrequired,permission: React.PropTypes.oneOf(['read','write']),userPermissions: React.PropTypes.object,}; // Checks that user permission for resource is the same or greater than required allowed() { const permissions = ['read','write']; const { permission,userPermissions } = this.props; const userPermission = userPermissions[resource] || 'none'; return permissions.indexOf(userPermission) >= permissions.indexOf(permission) } render() { if (this.allowed()) return { this.props.children }; } } export default connect(userPermissionsSelector)(Check)@H_502_6@其中userPermissionsSelector将是这样的:(store)=> store.userPermisisons并返回用户权限对象.
然后使用Check包装protected元素:
<Check resource="models" permission="write"> <Button>Edit model</Button> </Check>@H_502_6@有人做过这样的事吗?有比这更“优雅”的解决方案吗?
谢谢!
附:当然,用户权限也将在服务器端进行检查.
我写的是HOC反应路由器风格.
基本上我有我的PermissionsProvider,我在其中初始化用户权限.我有另一个withPermissions HOC,它将我之前提供的权限注入到我的组件中.
因此,如果我需要检查该特定组件的权限,我可以轻松访问它们.
// PermissionsProvider.js import React,{ Component } from "react"; import PropTypes from "prop-types"; import hoistStatics from "hoist-non-react-statics"; class PermissionsProvider extends React.Component { static propTypes = { permissions: PropTypes.array.isrequired,}; static contextTypes = { permissions: PropTypes.array,}; static childContextTypes = { permissions: PropTypes.array.isrequired,}; getChildContext() { // maybe you want to transform the permissions somehow // maybe run them through some helpers. situational stuff // otherwise just return the object with the props.permissions // const permissions = doSomething(this.props.permissions); // maybe add some validation methods return { permissions: this.props.permissions }; } render() { return React.Children.only(this.props.children); } } const withPermissions = Component => { const C = (props,context) => { const { wrappedComponentRef,...remainingProps } = props; return ( <Component permissions={context.permissions} {...remainingProps} ref={wrappedComponentRef} /> ); }; C.displayName = `withPermissions(${Component.displayName || Component.name})`; C.WrappedComponent = Component; C.propTypes = { wrappedComponentRef: PropTypes.func }; C.contextTypes = { permissions: PropTypes.array.isrequired }; return hoistStatics(C,Component); }; export { PermissionsProvider as default,withPermissions };@H_502_6@好的,我知道这是很多代码.但这些是HOC(你可以了解更多here).
A higher-order component (HOC) is an advanced technique in React for
reusing component logic. HOCs are not part of the React API,per se.
They are a pattern that emerges from React’s compositional nature.
Concretely,a higher-order component is a function that takes a
component and returns a new component.基本上我这样做是因为我受到路由器反应的启发.
每当你想知道一些路由的东西,你可以添加装饰器@withRouter,他们将道具注入你的组件.那么为什么不做同样的事呢?>首先,您必须使用提供程序设置权限
>然后在检查权限的组件上使用withPermissions装饰器//App render return ( <PermissionsProvider permissions={permissions}> <SomeStuff /> </PermissionsProvider> );@H_502_6@在SomeStuff里面你有一个广泛传播的工具栏来检查权限?
@withPermissions export default class Toolbar extends React.Component { render() { const { permissions } = this.props; return permissions.canDoStuff ? <RenderStuff /> : <HeCantDoStuff />; } }@H_502_6@如果您不能使用装饰器,则可以像这样导出工具栏
export default withPermissions(Toolbar);@H_502_6@这是我在实践中展示的代码框:
https://codesandbox.io/s/lxor8v3pkz
笔记:
>我真的非常简化了权限,因为该逻辑来自您的结束,为了演示目的,我简化了它们.>我假设权限是一个数组,这就是为什么我检查HOC中的PropTypes.array>这是一个非常漫长而复杂的答案,我试图用最好的能力表达出来.请不要在这里和那里烧掉我的一些错误:)