Я пытаюсь создать контроль доступа на основе ролей, используя Mon goose, React и Redux. Я думал, что это будет легкая задача, но я полностью сбит с толку. Я просто хочу добавить в список профилей список ролей и разрешений, в котором будет указано, какие разрешения имеет каждая роль для каждого действия. Затем я хочу функцию (или функции), которая проверит список разрешений для этой роли и вернет true, если роль пользователя может выполнить действие (ie редактирование определенного поля).
Мне также нужна другая функция, которая может устанавливать разрешения в зависимости от роли (ie кнопка будет отображаться только для администраторов). Поскольку эта функция проще двух, я начал с этой. Я пытался создать метод в своей схеме профиля, но когда я пытаюсь его использовать, я получаю сообщение об ошибке 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);