0

期待:

  • 只能获取 id 等于我的 id 的用户信息(保存在 JWT 令牌中)。

当前结果:

  • 我可以获取有关具有某些 id 的所有用户的信息。

创建此解决方案时使用了 Nest Js 文档。感谢您的帮助。

  1. /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
    export class GetUserPolicyHandler implements IPolicyHandler {
      handle(ability: AppAbility) {
        return ability.can(Action.Read, User);
      }
    }
  1. /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
@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. 用户解析器.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);
  }
}
4

0 回答 0