上下文
我使用Mongoose和NestJS定义了一个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接口中的InferSubject类推断出我的Mongoose模型的主题类型。但我不知道该用哪一门课来正确推断主语类型。
我错过了什么?
发布于 2022-02-08 18:31:21
因此,关键是在casl能力工厂中通过嵌套js注入猫模型。所以像这样的工厂应该能运作:
import {
Ability,
AbilityBuilder,
AbilityClass,
ExtractSubjectType,
InferSubjects,
} from '@casl/ability';
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { Cat, CatDocument } from '../cats/schemas/cat.schema';
import { User } from '../users/models/user.model';
export enum Action {
Manage = 'manage',
Create = 'create',
Read = 'read',
Update = 'update',
Delete = 'delete',
}
@Injectable()
export class CaslAbilityFactory {
constructor(
@InjectModel(Cat.name)
private catModel: Model<CatDocument>,
) {}
createForUser(user: User) {
const { can, build } = new AbilityBuilder(
Ability as AbilityClass<
Ability<[Action, InferSubjects<typeof this.catModel> | 'all']>
>,
);
can(Action.Read, this.catModel);
can(Action.Create, this.catModel);
can(Action.Update, this.catModel, {
createdBy: user.id,
});
if (user.isAdmin()) {
can(Action.Manage, 'all');
}
return build({
detectSubjectType: (item) =>
item.constructor as ExtractSubjectType<InferSubjects<typeof this.catModel> | 'all'>,
});
}
}https://stackoverflow.com/questions/69381918
复制相似问题