In this section of docs not all use-cases of guard usage explained clearly:
NestJS Docs - Claims-based authorization
CaslAbilityFactory implemented for these use-cases:
- Admins can manage (create/read/update/delete) all entities
- Users have read-only access to everything
- Users can update their articles (article.authorId === userId)
- Articles that are published already cannot be removed (article.isPublished === true)
and explained only the most trivial use-case:
Users have read-only access to everything
It's demonstrated with this controller method:
@Get()
@UseGuards(PoliciesGuard)
@checkPolicies((ability: AppAbility) => ability.can(Action.Read, Article))
findAll() {
return this.articlesService.findAll();
}
but how should I annotate a method to check the 3rd or 4th use-cases:
Articles that are published already cannot be removed:
(article.isPublished === true)
@Delete()
@UseGuards(PoliciesGuard)
@checkPolicies(?????????????????????????????)
delete(@Body() article: Article) {
return this.articlesService.delete(article.id);
}
Is it possible, at all? For this requirement PoliciesGuard or handler declared in @checkPolicies should be able to access method arguments.
How can controller method arguments be accessed from a guard?
Of course a workaround solution if you call ability.can(...) directly from controller method:
@Delete()
@UseGuards(SomeGuards but NOT PoliciesGuard)
delete(@Body() article: Article) {
const ability = this.caslAbilityFactory.createForUser(<<user from request>>);
if (!ability.can(Action.Delete, article)) {
throw new UnauthorizedException();
}
return this.articlesService.delete(article.id);
}
But this solution doesn't fit the original declarative pattern.