A set of opinionated NestJS extensions and modules
- @nestjsx/common - A set of NestJs decorators, interfaces and configuration for application modules bootstraping.
npm run test
Role and Attribute based Access Control for Nestjs π
License: MIT License
A set of opinionated NestJS extensions and modules
npm run test
ForRootAsync is not working. I have written it in app.module.ts.
AccessControlModule.forRootAsync({
inject: [RolePermissionsService],
useFactory: async (roleService: RolePermissionsService): Promise<RolesBuilder> => {
return new RolesBuilder(await roleService.getAll());
},
}),
roleService.getAll() return result as below array.
[
{ role: 'admin', resource: 'video', action: 'create:any', attributes: '*, !views' },
{ role: 'admin', resource: 'video', action: 'read:any', attributes: '*' },
{ role: 'admin', resource: 'video', action: 'update:any', attributes: '*, !views' },
{ role: 'admin', resource: 'video', action: 'delete:any', attributes: '*' },
{ role: 'user', resource: 'video', action: 'create:own', attributes: '*, !rating, !views' },
{ role: 'user', resource: 'video', action: 'read:any', attributes: '*' },
{ role: 'user', resource: 'video', action: 'update:own', attributes: '*, !rating, !views' },
{ role: 'user', resource: 'video', action: 'delete:own', attributes: '*' }
];
Hi all, I have a BaseController
and a BaseService
that are extended by all the other controllers and services of my resoursces. I'm trying to implement the UseRoles
decorator on the BaseController
without success.
I have tried two methods:
resource
in constructor
but I can't access the this
because "Object is possibly 'undefined'"
.AccessControlError: Invalid resource: ""
. In that case it seems that the UseRoles don't get the updated value passed in the constructor
// base.controller.ts
const resource = "";
export class BaseController<T> {
protected readonly baseService: BaseService<T>;
protected readonly resource: string;
protected constructor(baseService: BaseService<T>, collection: string) {
this.baseService = baseService;
this.resource = collection; // 1st method
resource = collection; // 2nd method
}
@UseGuards(ACGuard)
@UseRoles({ resource: this.resource, action: 'read', possession: 'own' }) // 1st method ==> error this Object is possibly 'undefined'
@UseRoles({ resource: resource, action: 'read', possession: 'own' }) // 2nd method error AccessControlError: Invalid resource: ""
@Get()
findAll(): Promise<T[]> {
return this.baseService.findAll();
}
}
// cat.controllers.ts
export class CatController extends BaseController<Cat> {
constructor(private readonly catService: CatService) {
super(catService, 'cat');
}
}
// dog.controllers.ts
export class DogController extends BaseController<Dog> {
constructor(private readonly dogService: DogService) {
super(dogService, 'dog');
}
}
Thanks in advance
Tengo este problema mi rol es un Entity Rol y no un array de strings, por esta razΓ³n obtengo este error
AccessControlError: Invalid role(s): []
Existe soporte para esto, debido a que mi lΓ³gica es de uno a muchos entre un Rol y un User en la base de datos.
}
"nombre": "admin",
"nombreUsuario": "admin",
"email": "[email protected]",
"rol": {
"id": 1,
"appRol": "administrador"
}
}
there are multiple security issue to fix
When roles array in user object is empty (no roles assigned to user) then it throws an error instead of giving Forbidden Resource exception
AccessControlError: Invalid role(s): []
Is behavior meant to be like this?
There is a lot of unnecessary peer dependencies, we dont need them because its not in use
import { RolesBuilder } from "nest-access-control";
import { Role } from "@prisma/client";
export const roles: RolesBuilder = new RolesBuilder();
roles
.grant(Role.USER).createOwn('users').deleteOwn('users').readAny('users').updateOwn('users')
.grant(Role.ADMIN).extend(Role.USER).updateAny('users').deleteAny('users');
@UseRoles({ possession: 'any', action: 'update', resource: "users" })
@Patch(':id')
update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto, @UserRoles() userRoles: any) {
console.log(userRoles);
return this.userService.update(id, updateUserDto);
}
Hi community,
I've just started working with NestJS and I needed to implement access-control in front-end(Angular) and back-end. I found this PR very helpful but I'm wondering if we could store the roles in database instead of a file, so they would be dynamic.
Do you guys have any Ideas ?
I had a quick look at the library but I can't see any docs around these 2 features:
We want to implement those two features and I was wondering if you have any thoughts or plans for those.
When trying use InjectRolesBuilder
get error: TypeError: metatype is not a constructor
constructor(@InjectRolesBuilder() private readonly roleBuilder: RolesBuilder) {}
TypeError: metatype is not a constructor
at Injector.instantiateClass (...\node_modules\@nestjs\core\injector\injector.js:214:19)
at callback (...\node_modules\@nestjs\core\injector\injector.js:67:41)
at process._tickCallback (internal/process/next_tick.js:68:7)
Hi i'm trying to grant all CRUD permissions to my admin user for every resource I thought using *
roles
.grant(AppRoles.ADMIN)
.createAny("*")
.readAny("*")
.updateAny("*")
.deleteAny("*")
would work , but it throws an error, "cannot use reserved name", How can I implement this so I don't write down all the resources ?
thanks,
Hello,
What if you're running a node cluster and a user changes roles/permissions. Since it's all being captured on the server instance, each node cluster would have to be updated as well. Is there a way to use redis? Or how would this be handled?
Thanks
Hi! The new change introduced here #63
Breaks exisitng projects, I'd suggest maybe using inline require so that it's only imported if needed? My project doesn't use graphql and I don't feel like adding it just to satisfy my pipeline. Thanks!
Hi.
Recent version of package.json
has critical problem to describe the version ranges of @nestjs/graphql
package.
When I tried to add recent version of this package with my project using @nestjs/[email protected],
β *** git:(release/v0.2) β npm install nest-access-control --save
npm WARN ERESOLVE overriding peer dependency
npm WARN While resolving: [email protected]
npm WARN Found: @nestjs/[email protected]
npm WARN node_modules/@nestjs/graphql
npm WARN peer @nestjs/graphql@"^10.0.0" from @nestjs/[email protected]
npm WARN node_modules/@nestjs/apollo
npm WARN @nestjs/apollo@"^10.0.0" from the root project
npm WARN 1 more (the root project)
npm WARN
npm WARN Could not resolve dependency:
npm WARN peer @nestjs/graphql@"^10.0.0" from @nestjs/[email protected]
npm WARN node_modules/@nestjs/apollo
npm WARN @nestjs/apollo@"^10.0.0" from the root project
npm WARN ERESOLVE overriding peer dependency
npm WARN While resolving: [email protected]
npm WARN Found: @nestjs/[email protected]
npm WARN node_modules/@nestjs/graphql
npm WARN peer @nestjs/graphql@"^10.0.0" from @nestjs/[email protected]
npm WARN node_modules/@nestjs/apollo
npm WARN @nestjs/apollo@"^10.0.0" from the root project
npm WARN 1 more (the root project)
npm WARN
npm WARN Could not resolve dependency:
npm WARN peerOptional @nestjs/graphql@"^7.0.0 | ^8.0.0 | ^9.0.0 | ^10.0.0" from [email protected]
npm WARN node_modules/nest-access-control
npm WARN nest-access-control@"*" from the root project
npm WARN ERESOLVE overriding peer dependency
npm WARN While resolving: [email protected]
npm WARN Found: @nestjs/graphql@undefined
npm WARN node_modules/@nestjs/graphql
npm WARN @nestjs/graphql@"^10.0.0" from the root project
npm WARN
npm WARN Could not resolve dependency:
npm WARN peerOptional @nestjs/graphql@"^7.0.0 | ^8.0.0 | ^9.0.0 | ^10.0.0" from [email protected]
npm WARN node_modules/nest-access-control
npm WARN nest-access-control@"*" from the root project
According to syntax definition of dependencies section in package.json
from official document (https://docs.npmjs.com/cli/v8/configuring-npm/package-json#dependencies),
the version of dependent package which allow multiple versions should divided by ||
operator, not |
.
Currently, packages.json
describe the version ranges of @nestjs/graphql
using |
operator.
"peerDependencies": {
"@nestjs/graphql": "^7.0.0 | ^8.0.0 | ^9.0.0 | ^10.0.0"
},
"peerDependenciesMeta": {
"@nestjs/graphql": {
"optional": true
}
}
version 2.0.1
AccessControlModule.forRootAsync({
inject: [RoleService],
useFactory: async (service: RoleService) => {
return new RolesBuilder(await service.factory());
},
}),
and d.ts
is
static forRootAsync(options: {
inject?: Provider[];
useFactory: (...args: any) => RolesBuilder;
}): DynamicModule;
not allow promise<T>
to return
the error is
Type 'Promise<RolesBuilder>' is missing the following properties from type 'RolesBuilder': _grants, _isLocked, isLocked, getGrants
Hi,
how to connect this repo with CRUD (https://github.com/nestjsx/crud)?
OWN / ANY is a problem displaying the profile. I would like ADMIN to be able to see all the profiles and USER only his own - both views would be based on the same method in CRUD. How to make roles detect if an object in the database is added by a logged in user or someone else?
With Nest 7 just released it would be helpful to have a new release that support it.
One thing that I noticed broke is the @UserRoles()
decorator.
It can't find the user object on the request anymore since request is not passed into the create param decorator factory. createParamDecorator now expects a ExecutionContext
instead.
From the migration docs
// Before
import { createParamDecorator } from '@nestjs/common';
export const User = createParamDecorator((data, req) => {
return req.user;
});
// After
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
export const User = createParamDecorator(
(data: unknown, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
return request.user;
},
);
In many cases, it is necessary and useful to know the roles and permissions of an API on the front-side.
I have not found any use cases that serve this purpose.
It would be useful to have an endpoint that serves the list of roles and their associated permissions.
@Module({
imports: [
AccessControlModule.forRoles({
roles: roles,
serveEndpoint: '/permissions'
})
],
controllers: [AppController],
providers: [AppService]
})
export class AppModule {}
REQUEST: /permissions
RESPONSE:
[
{
"rolename": "ADMIN",
"permissions": [
{
"name": "video",
"can_create": {
"own": "true",
"any": "false"
},
"can_read": {
"own": "true",
"any": "false"
},
"can_remove": {
"own": "true",
"any": "false"
},
"can_update": {
"own": "true",
"any": "false",
"fields": [
"someField", "otherField"
]
},
"can_remove": {
"own": "true",
"any": "false"
},
"can_update": {
"own": "true",
"any": "false",
"fields": [
"someField", "otherField"
]
}
},
{
"name": "other",
"can_create": {
"..."
},
"can_read": {
"..."
},
"can_remove": {
"..."
},
"can_update": {
"..."
}
},
"..."
]
}
]
Thanks for your time & effort π
I build a user, role, permission table and implement some method what I need.
I found this library , I think I can only create user table only, but i want to connect this library and I don't know how to do.
Or...I misunderstand this library use for?
Hello,
Thanks for the lib, I appreciate it.
Is it possible to pass a value that should be checked on the user object other than roles
for the list of permissions?
Say I have a user that it authenticated and the is like this:
{
id: 1,
email: "",
permissions: // Array of permissions that should be used instead of roles
}
Instead of using the forRootAsync
method, can we pass this value to the guard or something?
I am using the forRootAsync
method to load roles dynamically from the database however I am getting an error. I am a newbie to Nestjs, so please let me know if I am doing something wrong
Error: Nest can't resolve dependencies of the __roles_builder__ (?). Please make sure that the argument at index [0] is available in the AccessControlModule context.
I am trying to to import the AccessControlModule
in the root module and I have a RolesService
to inject as a dependency in the forRootAsync
method. The code is below
AccessControlModule.forRootAsync({
inject: [{
provide: ROLE_REPO,
useClass: Role
}],
useFactory: (service: repo) => {
return new RolesBuilder([
...adminGrants // testing local file grants
]);
}
})
Is it possible to define a simple RBAC system ('USER', 'EDITOR', 'ADMIN') and guarding the routes by user's role without having to define all permissions? Something like:
# app.roles.ts
import { RolesBuilder } from 'nest-access-control';
export enum AppRoles {
USER = 'USER',
EDITOR = 'EDITOR',
ADMIN = 'ADMIN',
}
export const roles: RolesBuilder = new RolesBuilder();
roles
.grant(AppRoles.USER)
.grant(AppRoles.EDITOR)
.extend(AppRoles.USER)
.grant(AppRoles.ADMIN)
.extend(AppRoles.EDITOR)
# app.controller.ts
@Get('test')
@UseGuards(JwtAuthGuard, ACGuard)
@UseRoles({role: 'ADMIN'}) // <=== Only admin access
test() {
...
}
I see that in the original interface can be defined the role
property that sounds good for my case, but it seems that your role.interface.ts
accept only resource
, action
and possession
. Or I'm missing something?
Thanks in advance
First off, thanks for your work!
I wanted to ask why in onury/accesscontrol the action also includes the possession, e.g. create:any
, read:own
and so on, while this package has separated action and possession? It seems that it only increases the boilerplate that we have to decorate each endpoint with.
AccessControlModule
AccessControlModule.forRootAsync({
imports: [SharedModule],
inject: [PrismaService],
useFactory: async (prismaService: PrismaService): Promise<RolesBuilder> => {
let roles = await prismaService.role.findMany({
where: {}, include: {
grants: { include: { permisssion: true } }
}
})
let result = roles.map(role => {
return role.grants.map(grant => {
let { resource, action, attributes } = grant.permisssion
return { role: role.name, resource, action, attributes }
})
})
if (result) {
let grants = []
result.forEach((grant) => grants = grants.concat(grant))
return new RolesBuilder(grants)
}
return new RolesBuilder([])
}
})
When I changed grant list in database. How do I reload grant list ?
Is there any options to set new grant list run time like when a new permission is set after bootstrapping nestjs?
I have set up all the roles properly and have used decorators in my controller, but it throws an error. What am I doing wrong here, I followed the documentation.
Roles
appRoles
.grant('superadmin')
.createAny(['clients', 'users'])
.readAny(['clients', 'users'])
.updateAny(['clients', 'users'])
.deleteAny(['clients', 'users'])
Controller
@UseGuards(JwtAuthGuard, ACGuard)
@UseRoles({
resource: 'users',
action: 'read',
possession: 'any',
})
@Get()
allUsers(@UserRoles() userRoles: any) {
console.log(userRoles);
return this.userService.findAll();
}
req.user
gives
{
id: 'uuid',
firstName: 'John',
lastName: 'John',
email: '[email protected]',
createdAt: 2020-04-23T12:15:41.494Z,
updatedAt: 2020-04-23T12:15:41.494Z,
roles: [ 'superadmin' ]
}
The error
[Nest] 29258 - 04/28/2020, 12:11:35 PM [ExceptionsHandler] Cannot read property 'roles' of undefined +14527ms
TypeError: Cannot read property 'roles' of undefined
at /redacted/node_modules/nest-access-control/decorators/user-roles.decorators.js:11:45
at /redacted/node_modules/@nestjs/core/helpers/context-utils.js:32:28
at resolveParamValue (/redacted/node_modules/@nestjs/core/router/router-execution-context.js:139:31)
at Array.map (<anonymous>)
at pipesFn (/redacted/node_modules/@nestjs/core/router/router-execution-context.js:144:45)
at /redacted/node_modules/@nestjs/core/router/router-execution-context.js:36:36
at InterceptorsConsumer.intercept (/redacted/node_modules/@nestjs/core/interceptors/interceptors-consumer.js:10:20)
at /redacted/node_modules/@nestjs/core/router/router-execution-context.js:45:60
at processTicksAndRejections (internal/process/task_queues.js:93:5)
at async /redacted/node_modules/@nestjs/core/router/router-proxy.js:8:17
Hi!
Actually nestjs-access-control is supporting Graphql?
I have an error when I do a mutation:
"Type Error: Cannot read property "user" of undefined
at ACGuard.getUser
at ACGuard.gerRoles
at ACGuard.canActivate
I changed the code from library directly
the code into ACGuard class in file access-control.guard.js
async getUser(context) {
// const request = context.switchToHttp().getRequest();
// return request.user;
const request = GqlExecutionContext.create(context).getContext().req;
return request.user;
}
To the best of my knowledge the context.switchToHttp().getRequest()
is only for REST. In Graphql should be used
GqlExecutionContext.create(context).getContext().req;
After changing the file, the error did not appear again and my code run as I expected.
Please tell if this is correct or if it exists other way to do this.
Thanks!
In Access Control docs it says
Note that own requires you to also check for the actual possession
and here it shows how to do it, but I am not sure how to check actual possession with nest-access-control.
So, please add more examples, at least for the roles and actions you have mentioned in app.roles.ts, I would really appreciate it.
By default if you have an unknown role the server throws an error:
[Nest] 12948 - 2020-05-15 17:03:24 [ExceptionsHandler] Role not found: "ASDFASDF" +325454ms
AccessControlError: Role not found: "ASDFASDF"
and returns an object like this:
{
"statusCode": 500,
"message": "Internal server error"
}
In my opinion ACL should just ignore this unknown role. What do you think?
Hi Nestjs Community!
As I'm still discovering the Nestjs framework and its awesome community, I've found this very nice little package :)
It is very convenient and it allowed me to implement quite easily some ABAC control on the API I'm working on.
Nevertheless, the only Access Control guard it offers (ACGuard
) is not compatible with the context request used within GraphQL resolvers.
So I was wondering if you were thinking about implementing either an additional guard or even making the actual one compatible with both classical and graphql requests.
Actually, I think the implementation would be quite straightforward and I would gladly participate in.
Have a nice day!
I saw in ACGuard that it is getting roles from user (user.roles), but i'm just using user.role. What can i do for the ACGuard to use just user.role?
How can I use filter
function in the controller to return the filtered data?
To filter data with all user roles rules we need acess to permission
object.
A user has the director role, he belongs to a company, he can also create and edit work groups that belong to that company. How can I get him to edit all the groups belonging to his own company, but not the groups of other companies?
///
Nest recently updated the way to set metadata, instead of @ReflectMetadata() it is @SetMetadata().
The sample contains this code
roles
.grant(AppRoles.USER_CREATE_ANY_VIDEO) // define new or modify existing role. also takes an array.
.createOwn('video') // equivalent to .createOwn('video', ['*'])
.deleteOwn('video')
.readAny('video')
.grant(AppRoles.ADMIN_UPDATE_OWN_VIDEO) // switch to another role without breaking the chain
.extend(AppRoles.USER_CREATE_ANY_VIDEO) // inherit role capabilities. also takes an array
.updateAny('video', ['title']) // explicitly defined attributes
.deleteAny('video');
What exactly does the title attribute do in the "updateAny" line?
Where is it checked?
the user roles decorator except that the user object is must be in the request, in the case that it isn't in the request the code get exception.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.