Intro
Я реализую простое MEAN-приложение с токеном JWT для аутентификации.Это приложение позволяет вам создать учетную запись, а затем создать собственную группу или присоединиться к существующей.У каждой группы есть определенные роли, которые администратор группы назначает каждому пользователю.Вот мои схемы, которые, надеюсь, помогут вам лучше понять мое решение.
Схема пользователя
_id: {
type: String,
default: function () { return new mongo.ObjectId().toString() }
},
email: {
type: String,
required: true,
unique: true
},
displayName: {
type: String
},
hash: {
required: true,
type: String
}
Схема группы
_id: {
type: String,
default: function () { return new mongo.ObjectId().toString() }
},
groupName: String,
ownerUser: {
type: String,
ref: 'User'
},
userList: [
{
user: {
type: String,
ref: 'User'
},
role: {
type: String,
ref: 'Role'
}
}
]
Схема роли
_id: {
type: String,
default: function () { return new mongo.ObjectId().toString() }
},
groupId: String,
roleName: String,
access: [{
path: String,
allowed: Boolean
}]
Как это работает
Регистрация пользователя / вход в систему -> Создать группу или присоединиться к существующей -> Администратор группы назначает роль пользователю.
- В группах будет примерно 250 пользователей.
- В группе может быть несколько ролей (10-15).
- Пользователь может присоединиться к нескольким группам
Экспресс-часть
пример маршрута
router.get('/restricted', JWTAuth, userProject, userRole, (res, req, next) => {
res.send("ok")
})
access.js
export const JWTAuth = passportAuth('jwt', {session: false});
export const userProject = async (req, res, next) => {
const userProject = await GroupModel.findOne({ _id: req.body.groupId, "userList.user" : req.user._id })
if(userProject) {
req.project = userProject;
next()
}else{
res.sendStatus(401);
}
}
export const userRole = async (req, res, next) => {
const roleId = arrayFindByObjectValue(req.user._id, 'user', req.project.userList).role;
const userRole = await RoleModel.findOne({ _id: roleId })
req.role = userRole;
next();
}
export const arrayFindByObjectValue = (value, key, array) => {
for (var i = 0; i < array.length; i++) {
if (array[i][key] === value) {
return array[i];
}
}
}
другие попытки .. заполнить (любые улучшения в скорости)
export const userRolePopulate = async (req, res, next) => {
const userProject = await GroupModel.findOne({ _id: req.body.groupId, "userList.user" : req.user._id }, {"userList.$" : 1}).populate('userList.role');
req.role = userProject.userList[0].role;
next()
}
и агрегация (улучшение 15%)
const userProject: any = await GroupModel.aggregate([
{$match: {_id: req.body.groupId}},
{$project: {
userList: {$filter: {
input: '$userList',
as: 'user',
cond: {$eq: ['$$user.user', req.user._id]}
}},
_id: 0
}},
])
Вопрос
Теперь я надеюсь, вы понимаете мою ситуацию.При таком подходе мне нужно выполнить несколько запросов к базе данных, чтобы получить роль пользователя только для простого запроса.Я беспокоюсь о скорости.Каждый запрос занимал около 150 мсек с промежуточным программным обеспечением роли (1000 пользователей группы).Я думаю, что это решение будет излишне перегружать сервер.Есть ли лучшее решение?Должен ли я использовать какой-либо сеанс (без сохранения состояния JWT ..) или другой метод для временного хранения роли пользователя?Есть ли лучший дизайн базы данных для этого метода?
Я прочитал много статей о системах на основе ролей, но я никогда не сталкивался с этим конкретным решением.Спасибо за ответ.Если вам нужна дополнительная информация, пожалуйста, дайте мне знать, и я отредактирую свой ответ.