简体   繁体   English

使用 CASL 的 Nest JS 授权无法按预期工作

[英]Nest JS authorization with CASL doesn't work as expected

EXPECTING:期待:

  • Be able to get user info with id equal to my id only (which is saved in JWT token).只能获取 id 等于我的 id 的用户信息(保存在 JWT 令牌中)。

CURRENT RESULT:当前结果:

  • I am able to get info about all users with some id.我可以获取有关具有某些 id 的所有用户的信息。

Used Nest Js docs while creating this solution.创建此解决方案时使用了 Nest Js 文档。 Do appreciate your help.感谢您的帮助。

  1. /casl-ability.factory.ts /casl-ability.factory.ts
type Subjects = InferSubjects<typeof User | typeof Role | 'User'> | 'all';
export type AppAbility = Ability<[Action, Subjects]>;

export class CaslAbilityFactory {
  createForUser(userDataFromJWT: JwtAccessTokenInput) {
    const { can, cannot, build } = new AbilityBuilder<
      Ability<[Action, Subjects]>
    >(Ability as AbilityClass<AppAbility>);

    // TESTING THIS CASE
    can(Action.Read, User, {
      id: userDataFromJWT.sub,
    });

    return build({
      detectSubjectType: (item) =>
        item.constructor as ExtractSubjectType<Subjects>,
    });
  }

  private hasRole(roles: unknown[], role: UserRoles): boolean {
    return roles.includes(role);
  }
}
  1. /getUser.policyHandler.ts /getUser.policyHandler.ts
    export class GetUserPolicyHandler implements IPolicyHandler {
      handle(ability: AppAbility) {
        return ability.can(Action.Read, User);
      }
    }
  1. /types.ts /types.ts
export enum Action {
  Manage = 'manage',
  Create = 'create',
  Read = 'read',
  Update = 'update',
  Delete = 'delete',
}

export interface IPolicyHandler {
  handle(ability: AppAbility): boolean;
}

type PolicyHandlerCallback = (ability: AppAbility) => boolean;

export type PolicyHandler = IPolicyHandler | PolicyHandlerCallback;
  1. /policies.guard.ts /policies.guard.ts
@Injectable()
export class PoliciesGuard implements CanActivate {
  constructor(
    private reflector: Reflector,
    private caslAbilityFactory: CaslAbilityFactory,
  ) {}

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

    const ctx = GqlExecutionContext.create(context);
    const { user }: { user: JwtAccessTokenInput } = ctx.getContext().req;
    const ability = this.caslAbilityFactory.createForUser(user);

    return policyHandlers.every((handler) =>
      this.execPolicyHandler(handler, ability),
    );
  }

  private execPolicyHandler(handler: PolicyHandler, ability: AppAbility) {
    if (typeof handler === 'function') {
      return handler(ability);
    }
    return handler.handle(ability);
  }
}
  1. user.resolver.ts用户解析器.ts
@Resolver(() => User)
export class UserResolver {
  constructor(private readonly userService: UserService) {}

  @Query(() => User, { name: 'user' })
  @UseGuards(PoliciesGuard)
  @CheckPolicies(new GetUserPolicyHandler())
  @UseInterceptors(UserNotExistsByIDInterceptor)
  async findOne(@Args('id', { type: () => Int }) id: number): Promise<User> {
    return await this.userService.findOne(id);
  }
}

possible duplicate of NestJS + CASL + Mongoose: CASL cannot infer subject type from Mongoose Schema NestJS + CASL + ZCCADCDEDB567ABAE643E15DCF0974E503Z 可能重复:CASL 无法从 ZCCADCDEDB567ABAE643E15DCF0974E503Z 架构推断主题类型

if you're using mongoose you need to inject the model to allow InferSubjects to retrieve the type thus allowing you to use filters and fields.如果您使用 mongoose 您需要注入 model 以允许 InferSubjects 检索类型,从而允许您使用过滤器和字段。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM