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



预期:

  • 只能获取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. user.resolver.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);
}
}

NestJS+CASL+Mongoose可能重复:CASL无法从Mongoose Schema 推断主题类型

如果你使用mongoose,你需要注入模型,以允许InferSubject检索类型,从而允许你使用过滤器和字段。

相关内容

  • 没有找到相关文章

最新更新