getjerry / nest-casl

Casl integration for NestJS
MIT License
225 stars 29 forks source link

assertAbility throws 401 #645

Closed jophuijbers closed 1 year ago

jophuijbers commented 1 year ago

The function "assertAbility" on AccessService always throws a 401 Unauthorized error (hasAbility returns false). The code below is pretty much identical to the provided sample in the documentation. When I use the decorators, everything works as expected. What could cause this weird behavior?

NOT WORKING:

constructor(private readonly accessService: AccessService) {}

@UseGuards(JwtAuthGuard)
@Query(() => User, { nullable: true })
async user(@Args("id") id: string, @CaslUser() userProxy: UserProxy<AuthUser>) {
  const user = await userProxy.get();
  const subject = this.userService.findById(id);

  this.accessService.assertAbility(user, Actions.read, subject);

  return subject;
}

WORKING:

@UseGuards(JwtAuthGuard, AccessGuard)
@UseAbility(Actions.read, User, UserHook)
...

Here are the configured permissions, nothing special.

user({ user, can }) {
  can(Actions.read, User, { id: user.id });
  can(Actions.update, User, { id: user.id });
  can(Actions.delete, User, { id: user.id });
}
okkindel commented 1 year ago

I see a bug in the library code but I don't see an easy workaround. subject is just the key for our rules, what we are interested in is subjectInstance but both hasAbility and assertAbility take subject as the third argument.

jordigagomerino commented 1 year ago

I will try to make a PR maybe they can add it. But a workaround that worked for mi: Call the service and getAbility for the user you want

    const userAbility = this.myService.getAbility(request.user);

This way you have access to casl, Then call can and pass the action and subject, subject is a function from casl. It will ony acept string in typescript but you can cast to any so it will work, and the instance. This way worked for me. Hope it work for you.

 userAbility.can(Actions.update, subject(Filter as any, instance)),
jophuijbers commented 1 year ago

Thanks, the workaround works as expected!