我正在尝试使用Mongoose,React和Redux创建基于角色的访问控制。我以为这是一件容易的事,但我完全感到困惑。我只想向我的概要文件架构添加角色和权限列表,以列出每个角色对每个操作具有的权限。然后,我需要一个(或多个)函数来检查该角色的权限列表,如果用户的角色可以执行该操作(即编辑某个字段),则返回true。
我还想要另一个可以根据角色设置权限的功能(即,仅管理员可以看到一个按钮)。由于这是两个函数中比较容易的一个,因此我从这一个开始。我试图在Profile模式上创建一个方法,但是当我尝试使用它时,出现错误profile.hasRole is not a function
个人资料架构:
models/Proile.js
const mongoose = require('mongoose');
const ProfileSchema = new mongoose.Schema({
user:{
type: mongoose.Schema.Types.ObjectId,
ref:'user'
},
location:{
type:String,
},
tags:{
type:[String],
},
bio:{
type: String,
},
role:{
type:String,
default:'User'
},
website:{
type:String
},
youtube:{
type:String
},
githubusername:{
type: String,
},
facebook:{
type:String
},
linkedin:{
type:String
},
twitter:{
type:String
},
instagram:{
type:String
},
date:{
type: Date,
default: Date.now
}
});
ProfileSchema.permissions={
User:{
read:[
"location",
"tags",
"bio",
"role",
"website",
"youtube",
"githubusername",
"facebook",
"linkedin",
"twitter",
"instagram",
"date"
]
},
SuperUser:{
read:[
"location",
"tags",
"bio",
"role",
"website",
"youtube",
"githubusername",
"facebook",
"linkedin",
"twitter",
"instagram",
"date"
],
write:[
"location",
"tags",
"bio",
"website",
"youtube",
"githubusername",
"facebook",
"linkedin",
"twitter",
"instagram",
"date"
]
},
Admin:{
read:[
"location",
"tags",
"bio",
"role",
"website",
"youtube",
"githubusername",
"facebook",
"linkedin",
"twitter",
"instagram",
"date"
],
write:[
"location",
"tags",
"bio",
"role",
"website",
"youtube",
"githubusername",
"facebook",
"linkedin",
"twitter",
"instagram",
"date"
],
remove: true
}
}
ProfileSchema.methods.hasRole = function(role, permissions){
return permissions.contains(role) ? true : false;
}
module.exports = Profile = mongoose.model('profile', ProfileSchema);
在下面的代码中,我想检查用户是否具有管理员角色的超级用户。如果他们这样做,将出现一个编辑配置文件按钮。如果没有,它将显示一条消息,说明该概要文件未加载或他们没有权限(调试完成后我将删除它们,并且将什么也不显示)
client/src/components/profile/Profile.js
import React, { Fragment, useEffect } from 'react';
import PropTypes from 'prop-types';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import Spinner from '../layout/Spinner';
import ProfileTop from './ProfileTop';
import ProfileAbout from './ProfileAbout';
import ProfileSocial from './ProfileSocial';
import ProfileTitle from './ProfileTitle';
import { getProfileById } from '../../actions/profile';
const Profile = ({
getProfileById,
profile: { profile, loading },
auth,
match
}) => {
useEffect(() => {
getProfileById(match.params.id);
}, [getProfileById, match.params.id]);
return (
<Fragment>
{profile === null || loading ? (
<Spinner />
) : (
<Fragment>
<div className='card mb-3 profile-container bg-light'>
<ProfileTop profile={profile} />
<div className="col-md-8">
<div className="card-body">
<ProfileTitle profile={profile} />
<ProfileSocial profile={profile} />
<ProfileAbout profile={profile} />
</div>
</div>
</div>
<div>
<Link to='/profiles' className='btn btn-secondary'>
Back To Profiles
</Link>
{auth.isAuthenticated &&
auth.loading === false ?
((auth.user._id === profile.user._id || profile.hasRole(['SuperUser','Admin'])) ? (
<Link to='/edit-profile' className='btn btn-primary'>
Edit Profile
</Link>
): (<div>Cannot edit</div>)) :
<div>Profile not loaded</div>
}
</div>
</Fragment>
)}
</Fragment>
);
};
Profile.propTypes = {
getProfileById: PropTypes.func.isRequired,
profile: PropTypes.object.isRequired,
auth: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
profile: state.profile,
auth: state.auth
});
export default connect(
mapStateToProps,
{ getProfileById }
)(Profile);