我有一个使用React-Redux-KoaJs开发的应用程序,其中包含多个组件。我还拥有几种用户角色。现在,我想仅向特定角色显示一些按钮、表格和div,并隐藏其他角色的这些内容。请注意,我不想隐藏整个组件,而只是其中的一部分。有人能帮我吗?先谢谢了。
我有一个使用React-Redux-KoaJs开发的应用程序,其中包含多个组件。我还拥有几种用户角色。现在,我想仅向特定角色显示一些按钮、表格和div,并隐藏其他角色的这些内容。请注意,我不想隐藏整个组件,而只是其中的一部分。有人能帮我吗?先谢谢了。
您可以像 @Eudald Arranz 建议的那样,在每个组件中检查角色或权限。或者,您可以编写一个组件来为您检查权限。例如:
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
const ShowForPermissionComponent = (props) => {
const couldShow = props.userPermissions.includes(props.permission);
return couldShow ? props.children : null;
};
ShowForPermissionComponent.propTypes = {
permission: PropTypes.string.isRequired,
userPermissions: PropTypes.array.isRequired
};
const mapStateToProps = state => ({
userPermissions: state.user.permission //<--- here you will get permissions for your user from Redux store
});
export const ShowForPermission = connect(mapStateToProps)(ShowForPermissionComponent);
然后你可以像这样使用这个组件:
import React from 'react';
import { ShowForPermission } from './ShowForPermission';
cons MyComponent = props => {
return (
<div>
<ShowForPermission permission="DELETE">
<button>Delete</button>
</ShowForPermission>
</div>
);
}
注意这一点。如果某些角色的操作很重要,您应该始终在后端对它们进行验证。如果没有适当的验证,很容易在前端更改redux中存储的值,从而允许对角色进行恶意使用。
如果您想采取可能的方法,请按照以下步骤:
function mapStateToProps(state) {
const { user_roles } = state;
return { user_roles };
}
export default connect(mapStateToProps)(YourComponent);
render() {
return (
<div>
{this.props.user_roles.role === "YOUR_ROLE_TO_CHECK" && <ActionsComponent />}
</div>
);
}
只有在角色等于所需角色时,ActionsComponent
才会呈现。
再次强调,始终要在后端验证角色!
解决此问题的最佳做法是,简单地防止应用程序生成不必要的路由。而不是在每个路由上检查当前用户角色,生成只有用户有访问权限的路由。
So The Normal reouting is: To control the whole view:
const App = () => (
<BrowserRouter history={history}>
<Switch>
<Route path="/Account" component={PrivateAccount} />
<Route path="/Home" component={Home} />
</Switch>
</BrowserRouter>
export default App;
);
基于用户角色的路由:
import { connect } from 'react-redux'
// other imports ...
const App = () => (
<BrowserRouter history={history}>
<Switch>
{
this.props.currentUser.role === 'admin' ?
<>
<Route path="/Account" exact component={PrivateAccount} />
<Route path="/Home" exact component={Home} />
</>
:
<Route path="/Home" exact component={Home} />
}
<Route component={fourOFourErroPage} />
</Switch>
</BrowserRouter>
const mapStateToProps = (state) => {
return {
currentUser: state.currentUser,
}
}
export default connect(mapStateToProps)(App);
管理员用户将可以访问“账户”页面,其他用户只能访问“主页”,如果任何用户尝试访问其他页面,则会出现404页面错误。
希望这个解决方案对你有所帮助。
有关此方法的详细信息,请查看GitHub上的此存储库:基于角色的访问控制与react
要隐藏仅呈现组件:
{this.props.currentUser.role === 'admin' && <DeleteUser id={this.props.userId} /> }
所以,我已经想出了一种替代而简单的方法,在前端实现基于角色的访问控制(RBAC)。
在你的 redux store 状态中,创建一个名为 permissions 的对象(或者你可以随意取名),像这样:
const InitialState = {
permissions: {}
};
InitialState['permissions'] ={
canViewProfile: (role!=='visitor'),
canDeleteUser: (role === 'coordinator' || role === 'admin')
// Add more permissions as you like
}
第一个权限表示,如果你不是访客,可以查看个人资料。 第二个权限表示,只有管理员或协调员才能删除用户。 这些变量将根据已登录用户的角色保留 true 或 false。因此,在存储状态中,您将拥有一个权限对象,其中键表示权限,其值将根据您的角色决定。
然后在组件中使用存储状态获取权限对象。您可以使用连接进行此操作,如下所示:
const mapStateToProps = (state) => {
permissions : state.permissions
}
然后将这些属性连接到您的组件中,如下所示:
export default connect(mapStateToProps,null)(ComponentName);
接下来,您可以在组件内部的任何要有条件显示的特定元素上使用这些属性,就像这样:
{(this.props.permissions.canDeleteUser) && <button onClick={this.deleteUser}>Delete User</button>}
以上代码将确保仅在您具有删除用户的权限时才呈现删除用户按钮,即在您的存储状态权限对象中,canDeleteUser的值为true。
就是这样,您已经应用了基于角色的访问控制。您可以使用此方法,因为它易于扩展和可变,因为您将根据角色拥有所有权限。
希望这有所帮助!如果我漏掉了什么,请在评论中指出。 :-)
a && b || c && d || e
这种难以管理的情况。 - Greenexport const SecuedLink = ({ resource, text, url }) => {
const userContext = useSelector(state => {
return state.userContext;
});
const isAllowed = checkPermission(resource, userContext);
const isDisabled = checkIsDisabled(resource, userContext);
return (isAllowed && <Link className={isDisabled ? "disable-control" : ""} to={() => url}>{text}</Link>)
}
const getElement = (resource, userContext) => {
return userContext.resources
&& userContext.resources.length > 0
&& userContext.resources.find(element => element.name === resource);
}
export const checkPermission = (resource, userContext) => {
const element = getElement(resource, userContext);
return userContext.isAuthenticated && element != null && element.isAllowed;
}
export const checkIsDisabled = (resource, userContext) => {
const element = getElement(resource, userContext);
return userContext.isAuthenticated && element != null && element.isDisabled;
}
<SecuedLink resource='link-post-edit' url={`/post-edit/${post.id}`} text='Edit'></SecuedLink>
<SecuedLink resource='link-post-delete' url={`/post-delete/${post.id}`} text='Delete'></SecuedLink>
步骤可以是:
为了效率,您可以使用react-redux来存储和重用这个新构建的json菜单。
请记住,所有的操作都在客户端进行。您仍然需要为每个API请求实现适当的授权机制,以防止未经授权的访问。
props.userPermissions.includes
方法150多次或更多次。您为每个元素迭代相同的数组。这可能会减慢您的应用程序。 - GreenSet
中,或者如果你不喜欢使用可变集合,你可以使用 immutable.js 中的Set
。或者你也可以只使用一个Object
,其中键是权限名称,值是任何你想要的东西。 - Andrii Golubenko