React/Redux 应用程序中组件的权限检查
Permission checks from components in a React/Redux application
我正在尝试与构建 React 应用程序的团队合作,并试图找出创建 "higher-order" React 组件(包装另一个组件)的最佳方法,以与Redux 数据存储。
到目前为止,我的方法是创建一个模块,该模块包含一个函数,该函数 returns 一个新的 React 组件,具体取决于是否存在经过身份验证的用户。
export default function auth(Component) {
class Authenticated extends React.Component {
// conditional logic
render(){
const isAuth = this.props.isAuthenticated;
return (
<div>
{isAuth ? <Component {...this.props} /> : null}
</div>
)
}
}
...
return connect(mapStateToProps)(Authenticated);
}
这让我团队中的其他人可以轻松指定组件是否需要特定权限。
render() {
return auth(<MyComponent />);
}
如果您要执行基于角色的检查,这种方法很有意义,因为您可能只有几个角色。在这种情况下,您可以调用 auth(<MyComponent />, admin)
.
传递参数对于基于权限的检查变得笨拙。然而,在构建组件时在组件级别指定权限可能是可行的(以及在团队环境中可管理)。设置静态 methods/properties 似乎是一个不错的解决方案,但据我所知,es6 类 导出为函数,不会显示可调用方法。
有没有办法访问导出的 React 组件的 properties/methods,以便可以从包含组件访问它们?
如果您使用react-router
,推荐的授权方式是通过Route
组件中的onEnter
属性。
<Route path="/" component={Component} onEnter={Component.onEnter} />
参见docs。
这也是对您问题的回答:
Is there a way to access the properties/methods of an exported React component such that they can be accessed from a containing component?
所以只需将它们设为静态 properties/methods(如 Component.onEnter)。
onEnter 很棒,在某些情况下很有用。但是,这里有一些常见的身份验证和授权问题 onEnter 没有解决:
- 根据 redux store 数据决定authentication/authorization(有
一些解决方法)
重新检查 authentication/authorization 商店是否更新(但不是
当前路线)
重新检查 authentication/authorization 如果子路由发生变化
在受保护的路线下面
另一种方法是使用高阶组件。
您可以使用 Redux-auth-wrapper 提供高阶组件以便于阅读和为您的组件应用身份验证和授权约束。
要获取子方法,您可以使用:refs, callback and callback from refs
要获取儿童道具,您可以使用:this.refs.child.props.some or compInstance.props.some
方法和道具示例:
class Parent extends Component {
constructor(props){
super(props);
this.checkChildMethod=this.checkChildMethod.bind(this);
this.checkChildMethod2=this.checkChildMethod2.bind(this);
this.checkChildMethod3=this.checkChildMethod3.bind(this);
}
checkChildMethod(){
this.refs.child.someMethod();
console.log(this.refs.child.props.test);
}
checkChildMethod2(){
this._child2.someMethod();
console.log(this._child2.props.test);
}
checkChildMethod3(){
this._child3.someMethod();
console.log(this._child3.props.test);
}
render(){
return (
<div>
Parent
<Child ref="child" test={"prop of child"}/>
<ChildTwo ref={c=>this._child2=c} test={"prop of child2"}/>
<ChildThree returnComp={c=>this._child3=c} test={"prop of child3"}/>
<input type="button" value="Check method of child" onClick={this.checkChildMethod}/>
<input type="button" value="Check method of childTwo" onClick={this.checkChildMethod2}/>
<input type="button" value="Check method of childThree" onClick={this.checkChildMethod3}/>
</div>
);
}
}
class Child extends Component {
someMethod(){
console.log('someMethod Child');
}
render(){
return (<div>Child</div>);
}
}
class ChildTwo extends Component {
someMethod(){
console.log('someMethod from ChildTwo');
}
render(){
return (<div>Child</div>);
}
}
class ChildThree extends Component {
componentDidMount(){
this.props.returnComp(this);
}
someMethod(){
console.log('someMethod from ChildThree');
}
render(){
return (<div>Child</div>);
}
}
我找到了一篇文章 here,我在这里写了这篇文章的要点。
你可以像这样给你的组件添加一个道具
<Route path="/" component={App}>
//BOD routes
<Route authorisedUsers={['KR']} path="/home" component={HomeContainer} />
//HR routes
<Route authorisedUsers={['HR']} path="/hrhome" component={HRDashboardContainer} />
//common routes
<Route authorisedUsers={['KR', 'HR']} path="/notes" component={NotesContainer} />
然后在您的组件中添加以下代码,该代码呈现在 path='/'
Role based routing react redux
componentDidUpdate() {
const {
children, //Component to be rendered (HomeContainer if route = '/home')
pathname: {location}, //location.pathname gives us the current url user is trying to hit. (with react router)
profileId, //profileId required by profile page common to all user journeys.
role } = this.props;
this.reRoute(role, this.props.children, location.pathname, ProfileId)
}
decideRoute(role, ProfileId) { //decide routes based on role
if(role==='HR')
return 'hrhome';
else if(role==='KR')
return 'home';
else if(role==='USER'&&ProfileId)
return 'profile/'+ProfileId;
else
return '/error';
}
isAuthorised(authorisedUsers, role) {
return _.includes(authorisedUsers, role)
}
reRoute(role, children, path, ProfileId) {
if(role===null && path!=='/') // user hit a different path without being authenticated first
{
hashHistory.replace('/'); //this is where we implemented login
return;
}
let route = this.decideRoute(role, ProfileId) //if role has already been fetched from the backend, use it to decide the landing page for each role.
if(children) // if we already are on one of the user journey screens ...
{
const authorisedUsers = children.props.route.authorisedUsers
if(!this.isAuthorised(authorisedUsers,role)) //... and the user is not allowed to view this page...
hashHistory.replace(`/${route}/`); //... redirect him to the home page corresponding to his role.
}
else
hashHistory.replace(`/${route}/`); // if the user has just logged in(still on / page or login page), and we know his role, redirect him to his home page.
}//if none of these holds true, user is allowed to go ahead and view the page
这实质上是添加了一个网关检查,适用于您的所有容器,并将根据您的角色指导您。此外,如果您以某种方式打错了 url.
,它将不允许您访问
这似乎是一个非常有趣的可能性。我遇到了这个问题谷歌搜索同样的问题,这是一个新的图书馆,所以我认为 link 它不会伤害它,以防其他人可以得到它的帮助。我还没有决定是否要自己走这条路,因为我已经进入 Google-palooza 15 分钟了。它被称为CASL。
Link to the Article Explaining the Library
库中每个请求的示例代码:
if (ability.can('delete', post)) {
<button onClick={this.deletePost.bind(this}>Delete</button>
}
替换如下内容:
if (user.role === ADMIN || user.auth && post.author === user.id) {
<button onClick={this.deletePost.bind(this}>Delete</button>
}
作者在文章中进一步使用自定义组件得到:
<Can run="delete" on={this.props.todo}>
<button onClick={this.deleteTodo.bind(this}>Delete</button>
</Can>
它基本上允许开发人员在他们的代码中更具声明性,以便于使用和维护。
对于任何想通过开源项目快速修复它的人,您可以尝试使用 react-permissible。
- 根据用户管理特定组件的可见性
权限
- 在不允许用户查看时替换特定组件
它
- 根据用户管理特定视图的可访问性
权限
- 当不允许用户访问时触发回调
component/route
我正在尝试与构建 React 应用程序的团队合作,并试图找出创建 "higher-order" React 组件(包装另一个组件)的最佳方法,以与Redux 数据存储。
到目前为止,我的方法是创建一个模块,该模块包含一个函数,该函数 returns 一个新的 React 组件,具体取决于是否存在经过身份验证的用户。
export default function auth(Component) {
class Authenticated extends React.Component {
// conditional logic
render(){
const isAuth = this.props.isAuthenticated;
return (
<div>
{isAuth ? <Component {...this.props} /> : null}
</div>
)
}
}
...
return connect(mapStateToProps)(Authenticated);
}
这让我团队中的其他人可以轻松指定组件是否需要特定权限。
render() {
return auth(<MyComponent />);
}
如果您要执行基于角色的检查,这种方法很有意义,因为您可能只有几个角色。在这种情况下,您可以调用 auth(<MyComponent />, admin)
.
传递参数对于基于权限的检查变得笨拙。然而,在构建组件时在组件级别指定权限可能是可行的(以及在团队环境中可管理)。设置静态 methods/properties 似乎是一个不错的解决方案,但据我所知,es6 类 导出为函数,不会显示可调用方法。
有没有办法访问导出的 React 组件的 properties/methods,以便可以从包含组件访问它们?
如果您使用react-router
,推荐的授权方式是通过Route
组件中的onEnter
属性。
<Route path="/" component={Component} onEnter={Component.onEnter} />
参见docs。
这也是对您问题的回答:
Is there a way to access the properties/methods of an exported React component such that they can be accessed from a containing component?
所以只需将它们设为静态 properties/methods(如 Component.onEnter)。
onEnter 很棒,在某些情况下很有用。但是,这里有一些常见的身份验证和授权问题 onEnter 没有解决:
- 根据 redux store 数据决定authentication/authorization(有 一些解决方法)
重新检查 authentication/authorization 商店是否更新(但不是 当前路线)
重新检查 authentication/authorization 如果子路由发生变化 在受保护的路线下面
另一种方法是使用高阶组件。
您可以使用 Redux-auth-wrapper 提供高阶组件以便于阅读和为您的组件应用身份验证和授权约束。
要获取子方法,您可以使用:
refs, callback and callback from refs
要获取儿童道具,您可以使用:
this.refs.child.props.some or compInstance.props.some
方法和道具示例:
class Parent extends Component {
constructor(props){
super(props);
this.checkChildMethod=this.checkChildMethod.bind(this);
this.checkChildMethod2=this.checkChildMethod2.bind(this);
this.checkChildMethod3=this.checkChildMethod3.bind(this);
}
checkChildMethod(){
this.refs.child.someMethod();
console.log(this.refs.child.props.test);
}
checkChildMethod2(){
this._child2.someMethod();
console.log(this._child2.props.test);
}
checkChildMethod3(){
this._child3.someMethod();
console.log(this._child3.props.test);
}
render(){
return (
<div>
Parent
<Child ref="child" test={"prop of child"}/>
<ChildTwo ref={c=>this._child2=c} test={"prop of child2"}/>
<ChildThree returnComp={c=>this._child3=c} test={"prop of child3"}/>
<input type="button" value="Check method of child" onClick={this.checkChildMethod}/>
<input type="button" value="Check method of childTwo" onClick={this.checkChildMethod2}/>
<input type="button" value="Check method of childThree" onClick={this.checkChildMethod3}/>
</div>
);
}
}
class Child extends Component {
someMethod(){
console.log('someMethod Child');
}
render(){
return (<div>Child</div>);
}
}
class ChildTwo extends Component {
someMethod(){
console.log('someMethod from ChildTwo');
}
render(){
return (<div>Child</div>);
}
}
class ChildThree extends Component {
componentDidMount(){
this.props.returnComp(this);
}
someMethod(){
console.log('someMethod from ChildThree');
}
render(){
return (<div>Child</div>);
}
}
我找到了一篇文章 here,我在这里写了这篇文章的要点。 你可以像这样给你的组件添加一个道具
<Route path="/" component={App}>
//BOD routes
<Route authorisedUsers={['KR']} path="/home" component={HomeContainer} />
//HR routes
<Route authorisedUsers={['HR']} path="/hrhome" component={HRDashboardContainer} />
//common routes
<Route authorisedUsers={['KR', 'HR']} path="/notes" component={NotesContainer} />
然后在您的组件中添加以下代码,该代码呈现在 path='/'
Role based routing react redux
componentDidUpdate() {
const {
children, //Component to be rendered (HomeContainer if route = '/home')
pathname: {location}, //location.pathname gives us the current url user is trying to hit. (with react router)
profileId, //profileId required by profile page common to all user journeys.
role } = this.props;
this.reRoute(role, this.props.children, location.pathname, ProfileId)
}
decideRoute(role, ProfileId) { //decide routes based on role
if(role==='HR')
return 'hrhome';
else if(role==='KR')
return 'home';
else if(role==='USER'&&ProfileId)
return 'profile/'+ProfileId;
else
return '/error';
}
isAuthorised(authorisedUsers, role) {
return _.includes(authorisedUsers, role)
}
reRoute(role, children, path, ProfileId) {
if(role===null && path!=='/') // user hit a different path without being authenticated first
{
hashHistory.replace('/'); //this is where we implemented login
return;
}
let route = this.decideRoute(role, ProfileId) //if role has already been fetched from the backend, use it to decide the landing page for each role.
if(children) // if we already are on one of the user journey screens ...
{
const authorisedUsers = children.props.route.authorisedUsers
if(!this.isAuthorised(authorisedUsers,role)) //... and the user is not allowed to view this page...
hashHistory.replace(`/${route}/`); //... redirect him to the home page corresponding to his role.
}
else
hashHistory.replace(`/${route}/`); // if the user has just logged in(still on / page or login page), and we know his role, redirect him to his home page.
}//if none of these holds true, user is allowed to go ahead and view the page
这实质上是添加了一个网关检查,适用于您的所有容器,并将根据您的角色指导您。此外,如果您以某种方式打错了 url.
,它将不允许您访问这似乎是一个非常有趣的可能性。我遇到了这个问题谷歌搜索同样的问题,这是一个新的图书馆,所以我认为 link 它不会伤害它,以防其他人可以得到它的帮助。我还没有决定是否要自己走这条路,因为我已经进入 Google-palooza 15 分钟了。它被称为CASL。
Link to the Article Explaining the Library
库中每个请求的示例代码:
if (ability.can('delete', post)) {
<button onClick={this.deletePost.bind(this}>Delete</button>
}
替换如下内容:
if (user.role === ADMIN || user.auth && post.author === user.id) {
<button onClick={this.deletePost.bind(this}>Delete</button>
}
作者在文章中进一步使用自定义组件得到:
<Can run="delete" on={this.props.todo}>
<button onClick={this.deleteTodo.bind(this}>Delete</button>
</Can>
它基本上允许开发人员在他们的代码中更具声明性,以便于使用和维护。
对于任何想通过开源项目快速修复它的人,您可以尝试使用 react-permissible。
- 根据用户管理特定组件的可见性 权限
- 在不允许用户查看时替换特定组件 它
- 根据用户管理特定视图的可访问性
权限 - 当不允许用户访问时触发回调 component/route