0

我的问题是,使用 Actions 和 Subjects 工作得很好,但我添加的所有条件或字段都没有影响。我希望 ID 为 1 的用户不能删除具有其他 ID 的用户,但可以删除他自己我在我的应用程序模块中将警卫添加为全局警卫有人知道问题可能是什么吗?

我的代码:

能力.decorator.ts:

import { SetMetadata } from '@nestjs/common';
import { Subjects, Action } from './ability.factory';

export interface RequiredRule {
  action: Action;
  subject: Subjects;
}

export const CHECK_ABILITY = 'check_ability';
export const Ability = (...requirements: RequiredRule[]) =>
  SetMetadata(CHECK_ABILITY, requirements);

能力工厂.ts

import {
  Ability,
  AbilityBuilder,
  AbilityClass,
  ExtractSubjectType,
  InferSubjects,
} from '@casl/ability';
import { Injectable, Post } from '@nestjs/common';
import { id } from 'date-fns/locale';
import { Subject } from 'rxjs';
import { Measurement } from 'src/measurement/entities/measurement.entity';
import { Orchard } from 'src/orchard/entities/orchard.entity';
import { SensorType } from 'src/sensor-type/entities/sensor-type.entity';
import { Station } from 'src/station/entities/station.entity';
import { User } from 'src/user/entities/user.entity';

export enum Action {
  Manage = 'manage',
  Create = 'create',
  Read = 'read',
  Update = 'update',
  Delete = 'delete',
}

export type Subjects = InferSubjects<
  | typeof User
  | typeof Measurement
  | typeof Orchard
  | typeof SensorType
  | typeof Station
  | 'all'
>;

export type AppAbility = Ability<[Action, Subjects]>;

@Injectable()
export class AbilityFactory {
  createForUser(user: User) {
    const { can, cannot, build } = new AbilityBuilder<
      Ability<[Action, Subjects]>
    >(Ability as AbilityClass<AppAbility>);

    can(Action.Manage, User);

    can(Action.Read, User, { id: 38 });
    cannot(Action.Delete, User, { id: { $ne: user.id } });

    return build({
      // Read https://casl.js.org/v5/en/guide/subject-type-detection#use-classes-as-subject-types for details
      detectSubjectType: (item) =>
        item.constructor as ExtractSubjectType<Subjects>,
    });
  }
}

能力守卫.ts

import { ForbiddenError } from '@casl/ability';
import {
  CanActivate,
  ExecutionContext,
  ForbiddenException,
} from '@nestjs/common';
import { Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { CHECK_ABILITY, RequiredRule } from './ability.deco';
import { AbilityFactory, Action } from './ability.factory';

@Injectable()
export class AbilityGuard implements CanActivate {
  constructor(
    private reflector: Reflector,
    private abilityFactory: AbilityFactory,
  ) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const rules =
      this.reflector.get<RequiredRule[]>(CHECK_ABILITY, context.getHandler()) ||
      [];

    console.log(rules);


    const { user } = context.switchToHttp().getRequest();

    console.log(user);

    const ability = this.abilityFactory.createForUser(user);

    try {
      rules.forEach((rule) =>
        ForbiddenError.from(ability).throwUnlessCan(rule.action, rule.subject),
      );

      return true;
    } catch (error) {
      if (error instanceof ForbiddenError) {
        throw new ForbiddenException(error.message);
      }
    }
  }
}

4

0 回答 0