Reputation: 427
I have the following abilities defined in CaslAbilityFactory
:
if (auth.isAdmin) {
can(Action.Create, User);
can(Action.Read, "all");
can(Action.Manage, User);
can(Action.Update, User, ["email", "firstName", "lastName", "role"]);
can(Action.Delete, User);
cannot(Action.Delete, User, isOwner);
}
if (auth.isUser) {
can([Action.Read, Action.Update], User, isOwner);
}
Then, I have defined the following resolver:
@Mutation(() => User)
@UseGuards(PoliciesGuard)
@CheckPolicies(ability => ability.can(Action.Update, User))
async updateUser(
@Args("input") input: UpdateUserInput,
@CurrentAuth() auth,
): Promise<User> {
const ability = this.caslAbilityFactory.createForAuth(auth);
if (ability.cannot(Action.Update, { id: input.id }) {
throw new ForbiddenException();
}
return this.usersService.update(input.id, input);
}
The @CheckPolicies
decorator correctly ensures that only a user with the Update
action for users can call it, but I need to assert that for this specific one, can I update it? If the requester is the owner, it can. But how do you check that before loading the user?
An obvious solution is to load the user, run the check, then perform the update. Another more hacky solution would be to somehow cast it to new User({ id })
and run the check.
Is there a better solution for this?
Thanks,
Upvotes: 0
Views: 47
Reputation: 5390
There are few options to do this. 2 of them you mentioned. Another one is to convert casl conditions to database query and let db check conditions.
This is possible for casl-prisma. There is also some work done in this direction for other SQL libs but it hasn’t been finished.
Casting POJO to User
is the worst option because you reveals permissions to controller. You know that only owners can access this object that’s why you hardcode object shape so casl returns you expected result. BUT as soon as you change this permissions on casl level, you will also need to update your hardcoded POJO shape. So basically you loose flexibility which casl gives you - changing permissions in single place.
That’s why there are only 2 viable long term solutions:
Upvotes: 1