Lyrol is fully featured role management library for node.js. It allows you to easily create roles and manage permissions and authorize your users, and it supports various frameworks like
express
, koa
and next.js
.
You can install lyrol using npm:
npm install lyrol
or yarn:
yarn add lyrol
import { Role } from 'lyrol';
const role = new Role([
{
resource: 'user',
scopes: 'cr---',
},
{
resource: 'post',
scopes: 'crudl',
},
{
resource: 'comment',
scopes: 'crudl',
},
]);
console.log(role.canCreate('user')); // true
console.log(role.canRead('user')); // true
console.log(role.canUpdate('user')); // false
console.log(role.can('create', 'user')); // true
You can extend a role by using the extend
method. This will create a new role with the same permissions as the original role, plus any additional permissions you specify.
import { Role } from 'lyrol';
const role = new Role([
{
resource: 'user',
scopes: 'cr---',
},
{
resource: 'post',
scopes: 'crudl',
},
{
resource: 'comment',
scopes: 'crudl',
},
]);
const admin = new Role().extend(role).addPermissions([
{
resource: 'group',
scopes: 'crudl',
},
]);
or you can pass an array as a second argument to the extend
method instead of using the addPermissions
method.
import { Role } from 'lyrol';
const role = new Role([
{
resource: 'user',
scopes: 'cr---',
},
{
resource: 'post',
scopes: 'crudl',
},
{
resource: 'comment',
scopes: 'crudl',
},
]);
const admin = new Role().extend(role, [
{
resource: 'group',
scopes: 'crudl',
},
]);
The extend
method takes optional options as a second parameter. You can use the overwrite
option to overwrite a permission in the extended role add pass the new permissions as the permissions
.
import { Role } from 'lyrol';
const role = new Role([
{
resource: 'user',
scopes: 'cr---',
},
{
resource: 'post',
scopes: 'crudl',
},
{
resource: 'comment',
scopes: 'crudl',
},
]);
const admin = new Role().extend(role, {
overwrite: true,
permissions: [
{
resource: 'user',
scopes: 'crudl',
},
],
});
console.log(admin.canDelete('user')); // true
You can save the role to a database by using the toJSON
method. This will return JSON stringified permissions.
import { Role } from 'lyrol';
const role = new Role([
{
resource: 'user',
scopes: 'cr---',
},
{
resource: 'post',
scopes: 'crudl',
},
{
resource: 'comment',
scopes: 'crudl',
},
]);
const permissions = role.toJSON();
or use the toObject
for a javascript object.
import { Role } from 'lyrol';
const role = new Role([
{
resource: 'user',
scopes: 'cr---',
},
{
resource: 'post',
scopes: 'crudl',
},
{
resource: 'comment',
scopes: 'crudl',
},
]);
const permissions = role.toObject();
or use use the generate
method and pass the output type as the first argument.
import { Role } from 'lyrol';
const role = new Role([
{
resource: 'user',
scopes: 'cr---',
},
{
resource: 'post',
scopes: 'crudl',
},
{
resource: 'comment',
scopes: 'crudl',
},
]);
const permissions = role.generate('json');
You can load the role from your database by using the fromJSON
or fromObject
method.
import { Role } from 'lyrol';
const role = Role.fromJSON(
'{"user":{"create":false,"read":false,"update":false,"delete":false,"list":true},"post":{"create":true,"read":true,"update":true,"delete":true,"list":true},"comment":{"create":true,"read":true,"update":true,"delete":true,"list":true},"page":{"create":true,"read":true,"update":true,"delete":true,"list":true},"picture":{"create":false,"read":false,"update":true,"delete":true,"list":true}}'
);
role.canCreate('user'); // false
or
import { Role } from 'lyrol';
const role = Role.fromObject({
user: {
create: false,
read: false,
update: false,
delete: false,
list: true,
},
post: { create: true, read: true, update: true, delete: true, list: true },
comment: {
create: true,
read: true,
update: true,
delete: true,
list: true,
},
page: { create: true, read: true, update: true, delete: true, list: true },
picture: {
create: false,
read: false,
update: true,
delete: true,
list: true,
},
});
role.canCreate('user'); // false
You can create a new instance of the ExpressRoleManager
class and use the authorize
method to authorize a user.
import { ExpressRoleManager, Role } from 'lyrol';
import express from 'express';
const app = express();
const user = new Role([
{
resource: 'post',
scopes: 'crudl',
},
{
resource: 'comment',
scopes: 'crudl',
},
]);
const roleManager = new ExpressRoleManager({
roles: {
user,
},
resources: ['post', 'comment'],
});
interface IAuthRequest {
role: string;
permissions: any;
}
app.get(
'/comment',
(req, res, next) => {
(req as unknown as IAuthRequest).role = 'role1';
next();
},
roleManager.authorize({
resource: 'comment',
action: ['read', 'list'],
}),
(req, res) => {
res.send('Hello World!');
}
);
app.listen(3000, () => {
console.log('Example app listening on port 3000!');
});
The authorize
method takes multiple options as a parameter.
resource
- The resource to be accessed. Can be a string or an array of strings.action
- The action to authorize. Can be a string or an array of strings.roleKey
- The key of the role in the request object. Default isrole
.usePermissionKey
- It's a boolean value. If set totrue
theauthorize
with create a role from the permissions in the request object. Default isfalse
.permissionKey
- The key of the permissions in the request object. Default ispermissions
.loose
- It's a boolean value. If set totrue
theauthorize
method will authorize the user if the user has any of the actions. Default isfalse
.
You can pass a custom error handler and success handler to the instance of the ExpressRoleManager
class.
import { ExpressRoleManager, Role } from 'lyrol';
const roleManager = new ExpressRoleManager({
roles: {
user,
},
resources: ['post', 'comment'],
onError: (err, req, res, next) => {
res.status(403).send('Forbidden');
},
onSucess: (req, res, next) => {
res.send('Hello World!');
},
});
You can create a new instance of the KoaRoleManager
class and use the authorize
method to authorize a user.
import { KoaRoleManager, Role } from 'lyrol';
import Koa from 'koa';
import Router from 'koa-router';
const app = new Koa();
const user = new Role([
{
resource: 'post',
scopes: 'crudl',
},
{
resource: 'comment',
scopes: 'crudl',
},
]);
const roleManager = new KoaRoleManager({
roles: {
user,
},
resources: ['post', 'comment'],
onError: (err, ctx, next) => {
ctx.status = 403;
ctx.body = 'Forbidden';
},
onSucess: (ctx, next) => {
ctx.body = 'Hello World!';
},
});
interface IAuthCtx {
role: string;
permissions: any;
}
const router = new Router();
router.get(
'/comment',
async (ctx, next) => {
(ctx as unknown as IAuthCtx).role = 'role1';
await next();
},
roleManager.authorize({
resource: 'comment',
action: ['read', 'list'],
}),
async (ctx) => {
ctx.body = 'Hello World!';
}
);
app.use(router.routes());
app.listen(3000, () => {
console.log('Example app listening on port 3000!');
});
The authorize
method takes the same options as the authorize
method of the ExpressRoleManager
class.
You can create a new instance of the NextRoleManager
class and use the authorize
method to authorize a user.
import { NextRoleManager, Role } from 'lyrol';
import { NextApiRequest, NextApiResponse, NextApiHandler } from 'next';
const user = new Role([
{
resource: 'post',
scopes: 'crudl',
},
{
resource: 'comment',
scopes: 'crudl',
},
]);
const roleManager = new NextRoleManager({
roles: {
user,
},
resources: ['post', 'comment'],
onError: (err, req, res) => {
res.status(403).send('Forbidden');
},
});
const withAuth = (handler: NextApiHandler) => {
return (req: NextApiRequest, res: NextApiResponse) => {
(req as any).role = 'user';
handler(req, res);
};
};
const handler = roleManager.authorize(
{
resource: 'comment',
action: ['create', 'update'],
},
(req, res) => {
res.status(200).send('Hello World!');
}
);
export default withAuth(handler);
This project is licensed under the MIT License - see the LICENSE file for details