在NestJS防护中使用CASL



在文档的这一部分中,并不是所有保护使用的用例都解释清楚:
NestJS文档-基于声明的授权

为这些用例实现的CaslAbilityFactory:

  • 管理员可以管理(创建/读取/更新/删除(所有实体
  • 用户对所有内容都具有只读访问权限
  • 用户可以更新他们的文章(article.authorId===userId(
  • 无法删除已发布的文章(article.isPublished===true(

并只解释了最琐碎的用例:

用户可以只读访问的所有内容

用这种控制器方法进行了演示:

@Get()
@UseGuards(PoliciesGuard)
@checkPolicies((ability: AppAbility) => ability.can(Action.Read, Article))
findAll() {
return this.articlesService.findAll();
}

但是我应该如何注释一个方法来检查第三个或第四个用例:

已发布的文章无法删除:
(article.isPublishd==true(

@Delete()
@UseGuards(PoliciesGuard)
@checkPolicies(?????????????????????????????)
delete(@Body() article: Article) {
return this.articlesService.delete(article.id);
}

有可能吗?为此,在@checkPolicies中声明的PoliciesGuard或处理程序应该能够访问方法参数。

如何从保护访问控制器方法参数?

当然,一个变通的解决方案,如果你调用能力。可以(…(直接从控制器方法:

@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);
}

但是这个解决方案不符合最初的声明模式。

您可以在PolicyGuard中实现这一点。这在NestJS文档中有所提及

你的政策卫士会像这个

@Injectable()
export class PoliciesGuard extends RequestGuard implements CanActivate {
public constructor(private reflector: Reflector, private caslAbilityFactory: CaslAbilityFactory) {
super();
}
public async canActivate(context: ExecutionContext): Promise<boolean> {
const policyHandlers = this.reflector.get<PolicyHandler[]>(CHECK_POLICIES_KEY, context.getHandler()) || [];
const request = this.getRequest(context);
const { user } = request;
const ability = await this.caslAbilityFactory.createForUser(user?.userId);
return policyHandlers.every(handler => this.execPolicyHandler(handler, ability, request));
}
private execPolicyHandler(handler: PolicyHandler, ability: AppAbility, request: Request) {
if (typeof handler === 'function') {
return handler(ability, request);
}
return handler.handle(ability, request);
}
}

则checkPolicy将接受此功能

export class ReadArticlePolicyHandler implements IPolicyHandler {
handle(ability: AppAbility, request) {
const { query } = request;
const article = new Article();
article.scope = query.scope;
return ability.can(Action.Read, article) || ability.can(Action.Delete, article);
}
}

相关内容

  • 没有找到相关文章

最新更新