语境
我已经Cat
使用 Mongoose 和 NestJS 定义了一个模式:
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';
export type CatDocument = Cat & Document;
@Schema()
export class Cat {
@Prop({ required: true })
name: string;
@Prop({ required: true })
breed: string;
@Prop({ required: true })
createdBy: string;
// Other fields...
}
export const CatSchema = SchemaFactory.createForClass(Cat);
我还定义了一个使用 CASL 处理我的 API 授权的能力工厂:
import {
Ability,
AbilityBuilder,
AbilityClass,
ExtractSubjectType,
InferSubjects,
} from '@casl/ability';
import { Injectable } from '@nestjs/common';
import { Cat } from '../cats/schemas/cat.schema';
import { User } from '../users/models/user.model';
type Subjects = InferSubjects<typeof Cat | typeof User> | 'all';
export enum Action {
Manage = 'manage',
Create = 'create',
Read = 'read',
Update = 'update',
Delete = 'delete',
}
export type AppAbility = Ability<[Action, Subjects]>;
@Injectable()
export class CaslAbilityFactory {
createForUser(user: User) {
const { can, build } = new AbilityBuilder<
Ability<[Action, Subjects]>
>(Ability as AbilityClass<AppAbility>);
can(Action.Read, Cat);
can(Action.Create, Cat);
can(Action.Update, Cat, {
createdBy: user.id,
});
if (user.isAdmin()) {
can(Action.Manage, 'all');
}
return build({
detectSubjectType: (item) =>
item.constructor as ExtractSubjectType<Subjects>,
});
}
}
问题
当我尝试检查我的服务中的权限时(注意:用户不是管理员):
import {
ForbiddenException,
Injectable,
} from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { EditCatInput } from './dto/edit-cat.input';
import { Cat, CatDocument } from './schemas/cat.schema';
import { Action, CaslAbilityFactory } from '../casl/casl-ability.factory';
import { User } from '../users/models/user.model';
@Injectable()
export class CatsService {
constructor(
private readonly configService: ConfigService,
private readonly caslAbilityFactory: CaslAbilityFactory,
@InjectModel(Cat.name) private catModel: Model<CatDocument>,
) {}
// Other methods...
async update(id: string, input: EditCatInput, user: User): Promise<Cat> {
const updatedCat = await this.catModel
.findOne({
_id: { $eq: id },
deleted: { $eq: false },
})
.exec();
const ability = this.caslAbilityFactory.createForUser(user);
if (!ability.can(Action.Update, updatedCat)) {
throw new ForbiddenException(
'You cannot edit this cat.',
);
}
Object.assign(updatedCat, input);
await updatedCat.save();
return updatedCat;
}
}
ability.can(Action.Update, cat)
总是返回false
,而它应该是true
。
附加信息
ability.can
false
当用户不是管理员时返回任何操作。
我的猜测是 CASL 无法使用能力构建器接口中的Cat
类来推断我的 Mongoose 模型的主题类型。InferSubject
但我不知道使用哪个类来正确推断主题类型。
我错过了什么?