Лекция 19
const permissions = {
'/posts/create': 'user',
...
};
class AuthorizationService {
async checkPermissions(user, route) {
if (!permissions[route]) {
return;
}
if(!user) {
throw this.errors.accessDenied;
}
...
}
}
async checkPermissions(user, route) {
...
const role = user.isAdmin ? 'admin' : 'user';
if (permissions[route] !== role) {
throw this.errors.accessDenied;
}
}
async checkPermissions(user, route) {
...
const role = await this.rolesRepository
.findOne({
where: {
name: permissions[route]
}
});
const hasRole = await user.hasRole(role);
if (!hasRole) {
throw this.errors.accessDenied;
}
}
const permissions = {
'/posts/create': [{
resource: 'post',
action: 'create'
}],
...
};
async checkPermissions(user, route) {
...
if (!user.can(permissions[route])) {
throw this.errors.accessDenied;
}
}
const shouldHave = permissions =>
async (req, res, next) => {
await authorizationService
.checkPermissions(req.user, permissions);
next();
};
class PostsController {
constructor(postsService, cahceService) {
...
this.routes['/create'].unshift({
method: 'post',
cb: shouldHave([{
resource: 'post',
action: 'create'
}])
});
}
...
}
npm install acl
const acl = require('acl');
acl = new acl(new acl.memoryBackend());
// guest is allowed to view blogs
acl.allow('guest', 'blogs', 'view')
// allow function accepts arrays as any parameter
acl.allow(
'member',
'blogs',
['edit', 'view', 'delete']
)
acl.addUserRoles('joed', 'guest')
acl.addRoleParents('baz', ['foo', 'bar'])
acl.allow('admin', ['blogs', 'forums'], '*')
acl.isAllowed('joed', 'blogs', 'view', (err, res) => {
if(res){
console.log("User joed is allowed to view blogs")
}
})
acl.isAllowed(
'jsmith',
'blogs',
['edit', 'view', 'delete']
)
acl.allowedPermissions(
'james',
['blogs', 'forums'],
(err, permissions) => console.log(permissions)
)
[
{'blogs': ['get', 'delete']},
{'forums':['get', 'put']}
]
// req.url
// req.session.userId
app.put(
'/blogs/:id',
acl.middleware(),
(req, res, next) => { ... }
)
addUserRoles
removeUserRoles
userId {String|Number}
roles {String|Array}
callback {Function}
userRoles
userId {String|Number}
callback {Function}
roleUsers
rolename {String|Number}
callback {Function}
hasRole
userId {String|Number}
rolename {String|Number}
callback {Function}
addRoleParents
removeRoleParents
role {String}
parents {String|Array}
callback {Function}
removeRole
role {String}
callback {Function}
allow
roles {String|Array}
resources {String|Array}
permissions {String|Array}
callback {Function}
removeAllow
role {String}
resources {String|Array}
permissions {String|Array}
callback {Function}
allowedPermissions
userId {String|Number}
resources {String|Array}
callback {Function}
isAllowed
userId {String|Number}
resource {String}
permissions {String|Array}
callback {Function}
areAnyRolesAllowed
roles {String|Array}
resource {String}
permissions {String|Array}
callback {Function}
whatResources
role {String|Array}
permissions {String|Array} # optional
callback {Function}
middleware
numPathComponents {Number}
userId {String|Number|Function}
permissions {String|Array}
npm install casl
const { AbilityBuilder } = require('casl');
...
const ability = AbilityBuilder.define((can, cannot) => {
can('read', 'all');
can('manage', 'Post', { author: req.user.id });
cannot('delete', 'Post',
{ 'comments.0': { $exists: true } }
);
});
ability.can('read', 'Post') // true
ability.can('create', 'Post') // true
ability.can('comment', 'Post') // false
const post = new Post({ title: 'What is CASL?' })
ability.can('read', post) // true
function defineAbilitiesFor(user) {
return new Promise(resolve => {
resolve(AbilityBuilder.define((can, cannot) => {
can('read', 'Post');
if (user && user.hasRole('regular')) {
can('comment', 'Post'});
}
if (user && user.hasRole('premium')) {
can('comment', 'Post'});
can('manage', 'Post'}, { author: user.id });
}
if (user && user.hasRole('admin')) {
can('comment', 'Post'});
can('manage', 'Post'});
}
}));
});
}
const { AbilityBuilder, Ability } = require('casl')
function defineAbilitiesFor(user) {
return new Promise(resolve => {
const { rules, can, cannot }
= AbilityBuilder.extract()
...
resolve(new Ability(rules));
});
}
can('manage', 'Post') // CRUD
can('read', 'all')
can(['update', 'delete'], ['Post', 'Comment'])
Ability.addAlias('modify', ['update', 'delete'])
AbilityBuilder.define(can => {
can('modify', 'Post')
})
can(
'read',
'Project',
{ active: true, ownerId: user.id }
)
can(
'delete',
'Post',
{ 'comments.0': { $exists: false } }
)
// OR
can('read', 'Post', { published: true })
can('read', 'Post', { preview: true })
// Override
can('manage', 'Post')
cannot('delete', 'Post')
ability.update([]) // removes all rules
ability.update([{ subject: 'all', actions: 'read' }])
ability.on('update', ({ rules, ability }) => {
...
})
try {
const post = new Post({ private: true })
ability.throwUnlessCan('delete', post)
post.destroy()
} catch (error) {
if (error instanceof ForbiddenError) {
console.log('Access denied!')
}
}
res.json({
...,
rules: req.ability.rules
});
... on client side ...
const ability = new Ability(rules);