Я видел экспресс-пример, где способность сохраняется через промежуточное ПО в объекте req. Затем он использует следующий метод для оценки разрешений:
ForbiddenError.from(req.ability).throwUnlessCan('read', article);
Я хочу добиться того же. Моя идея состоит в том, чтобы сохранить возможность внутри экспресс-сеанса, который используется совместно с socket io websockets. Через обмен req.session
= socket.handshake.session
. Мой подход заключается в следующем: я делаю запрос из внешнего интерфейса, чтобы получить правила для обновления возможностей внешнего интерфейса. Бэкэнд сохраняет возможность внутри экспресс-сеанса:
// abilities.js file
import { Ability } from '@casl/ability';
export const defineAbilitiesFor = (rules) => {
return new Ability(rules);
};
export default defineAbilitiesFor;
// handler for express route to get permissions from the frontend
export const getPermissions = async (req, res) => {
...
rules.push({
action: ['view'],
subject: views,
});
// manage all own processes
rules.push({
action: ['manage'],
subject: 'Process',
conditions: {
userId: req.kauth.grant.access_token.content.sub,
},
});
// store ability in session
req.session.rules = defineAbilitiesFor(rules);
const token = jwt.sign({ token: packRules(rules) }, 'secret');
if (token) {
return res.status(200).json(token);
} else {
return res.status(400).json('Error');
}
...
Затем, когда происходит запрос веб-сокета, я хочу проверить в бэкэнде, есть ли у пользователя разрешения на выполнение этого действия:
ForbiddenError.from(socket.handshake.session.rules).throwUnlessCan('view', 'Process');
Однако это вызывает следующую ошибку:
TypeError: this.ability.relevantRuleFor is not a function
at ForbiddenError.throwUnlessCan
Кажется, что объект сеанса имеет правильный объект способности. Когда я использую console.log socket.handshake.session.rules
, я получаю следующий результат:
{
h: false,
l: {},
p: {},
'$': [
{ action: [Array], subject: 'Process', conditions: [Object] },
{ action: [Array], subject: [Array] },
{ action: [Array], subject: 'Process', conditions: [Object] }
],
m: {}
}
Также банка функционирует, и все остальное, что я пробовал, не работало. Я думаю, что нужно хранить простые правила как объект внутри сеанса, а затем обновлять класс способностей до того, как каждый запрос будет работать, но я не хочу этого делать. Я хочу сохранить способность прямо внутри сеанса, чтобы мне нужно было только выполнить throwUnlessCan или функции can.
Возможно ли это вообще, и если да, то как бы вы это сделали?
Пока спасибо.