当我多次使用导入PolicyModule.forFeature
时,PolicyModule
的下一次导入将覆盖PolicyStorage
中的门。
当我尝试通过调用PolicyProvider
CandidateModule
的{{1}}中使用CandidateEducationService
时
PolicyProvider
我收到异常await this.policy.denyAccessUnlessGranted('canDelete', education);
。
我在Gate by entity 'CandidateEducationEntity' not found
中输出PolicyStorage
并获得了CandidateEducationService
的阵列门
JobPolicy
但是我期待着
PolicyStorage {
gates:
[ { policy: [Function: JobPolicy], entity: [Function: JobEntity] } ]
}
我创建了一个动态模块PolicyStorage {
gates:
[ { policy: [Function: CandidateEducationPolicy], entity: [Function: CandidateEducationEntity] } ]
}
PolicyModule
@Module({})
export class PolicyModule {
public static forFeature(gates: PolicyGate[]): DynamicModule {
const providers: Provider[] = [
...gates.map(gate => gate.policy),
{
provide: PolicyStorage,
useValue: new PolicyStorage(gates),
},
PolicyProvider,
];
return {
module: PolicyModule,
imports: [
CommonModule,
],
providers,
exports: providers,
};
}
}
PolicyStorage
@Injectable()
export class PolicyStorage {
constructor(private gates: PolicyGate[]) {
console.log(this.gates);
}
public find(name: string): PolicyGate | null {
return this.gates.find(policy => policy.entity.name === name);
}
}
PolicyProvider
在其他模块中使用模块。示例:
@Injectable()
export class PolicyProvider<E, P> {
constructor(
private readonly moduleRef: ModuleRef,
private readonly gateStorage: PolicyStorage,
private readonly appContext: AppContextService,
) {
}
public async denyAccessUnlessGranted(methodNames: MethodKeys<P>, entity: E, customData?: any) {
if (await this.denies(methodNames, entity, customData)) {
throw new ForbiddenException();
}
}
public async allowAccessIfGranted(methodNames: MethodKeys<P>, entity: E, customData?: any) {
const allowed = await this.allows(methodNames, entity, customData);
if (!allowed) {
throw new ForbiddenException();
}
}
private async allows(methodNames: MethodKeys<P>, entity: E, customData?: any): Promise<boolean> {
const results = await this.getPolicyResults(methodNames, entity, customData);
return results.every(res => res === true);
}
private async denies(methodNames: MethodKeys<P>, entity: E, customData?: any): Promise<boolean> {
const results = await this.getPolicyResults(methodNames, entity, customData);
return results.every(res => res === false);
}
private async getPolicyResults(methodNames: MethodKeys<P>, entity: E, customData?: any): Promise<boolean[]> {
const methodNamesArray = Array.isArray(methodNames) ? methodNames : [methodNames];
const gate = this.findByClassName(entity.constructor.name);
const user = this.appContext.get('user');
const policy = await this.moduleRef.get<P>(gate.policy, {strict: false});
const results = [];
for (const methodName of methodNamesArray) {
results.push(!!await policy[methodName as string](entity, user, customData));
}
return results;
}
private findByClassName(name: string) {
const gate = this.gateStorage.find(name);
if (!gate) {
throw new RuntimeException(`Gate by entity '${name}' not found`);
}
return gate;
}
}
JobsModule
@Module({
imports: [
TypeOrmModule.forFeature(
[
JobEntity,
],
),
PolicyModule.forFeature([
{
policy: JobPolicy,
entity: JobEntity,
},
]),
],
controllers: [
ManagerJobsController,
],
providers: [
ManagerJobsService,
],
})
export class JobsModule {
}
CandidateModule
答案 0 :(得分:2)
Nest v6引入了请求范围的提供程序,请参见this answer。
所有模块及其提供者均为单例。如果您在同一模块中两次使用同一令牌注册提供者,则它将被覆盖。
如果您查看TypeOrmModule,则可以在每个实体的唯一registers its repository providers下看到它custom token:
export function getRepositoryToken(entity: Function) {
if (
entity.prototype instanceof Repository ||
entity.prototype instanceof AbstractRepository
) {
return getCustomRepositoryToken(entity);
}
return `${entity.name}Repository`;
}
因此,在您的情况下,您可以拥有功能getPolicyProviderToken
和getPolicyStorageToken
,并在这些标记下注册和注入您的提供程序,这些标记对于每个导入模块都是唯一的。