#decorator #nestjs
#декоратор #nestjs
Вопрос:
У меня есть пользовательский декоратор метода, подобный этому.
export function CustomDecorator() {
return applyDecorators(
UseGuards(JwtAuthGuard)
);
}
Внутри пользовательского декоратора я хочу получить заголовок запроса, но не уверен, как получить экземпляр запроса?
Комментарии:
1. Не могли бы вы добавить больше информации о том, что вы хотите сделать, пожалуйста? Я понял, что вы хотите получить доступ к заголовкам, но с какой целью?
2. У нас есть общий модуль аутентификации, в котором мы можем использовать JWT или GoogleAuth. Я хочу реализовать пользовательский декоратор, который применяет различные средства защиты на основе заголовков запроса.
Ответ №1:
Вы не сможете получить ExectuionContext
объект или Request
object в декораторе класса или метода, потому что эти декораторы запускаются немедленно в момент импорта. Что следует сделать вместо этого, так это создать, SuperGuard
который имеет ExecutionContext
доступный для него. В это SuperGuard
должны быть введены все другие средства защиты через constructor
, и в зависимости от заголовка вы должны вызвать / вернуть результат из вызванного средства защиты. Что-то вроде этого:
@Injectable()
export class SuperGuard implements CanActivate {
constructor(
private readonly jwtAuthGuard: JwtAuthGuard,
private readonly googleAuthGuard: GoogleAuthGuard,
) {}
canActivate(context: ExecutionContext) {
const req = context.switchToHttp().getRequest();
if (req.headers['whatever'] === 'google') {
return this.googleAuthGuard.canActivate(context);
} else {
return this.jwtAuthGuard.canActivate(context);
}
}
}
Комментарии:
1. Привет, Джей, я получаю эту ошибку. Ошибка: Nest не может разрешить зависимости RomeGuard (?). Пожалуйста, убедитесь, что аргумент JwtAuthGuard с индексом [0] доступен в контексте AuthModule. Возможные решения: — Если JwtAuthGuard является поставщиком, является ли он частью текущего AuthModule? — Если JwtAuthGuard экспортируется из отдельного @Module, импортируется ли этот модуль в AuthModule? @Module({ импортирует: [ /* модуль, содержащий JwtAuthGuard */ ] }) в инжекторе. lookupComponentInParentModules
2. Вам нужно убедиться, что везде, где вы используете,
SuperGuard
у вас естьJwtAuthGuard
иGoogleAuthGuard
добавлены какproviders
. Это можно сделать изGuardModule
, если вы того пожелаете3. Привет, Джей, я добавил это вот так
providers: [SharedDataAuthService, JwtStrategy, JwtAuthGuard],
, но он показывает эту ошибку.4. Всего хорошего, Джей. Мне также нужно добавить это в exports. Спасибо за вашу помощь.
5. Привет, Джей, у меня вопрос… Если декоратор Guard запускается немедленно в момент импорта, как он может перехватить запрос в ExecutionContext ? ^^
Ответ №2:
Мне удалось получить доступ к контексту выполнения в декораторе, используя Inject
внутри фабрики декоратора. Вот мой декоратор, который проглатывает ошибки, создаваемые методом, и возвращает предопределенное значение в случае исключения.
import { Injectable, Scope, Inject, ExecutionContext } from '@nestjs/common';
import { CONTEXT } from '@nestjs/graphql';
@Injectable({ scope: Scope.REQUEST })
export class ExceptionsHandler {
public constructor(@Inject(CONTEXT) private readonly context: ExecutionContext) {}
private integrationsRequestErrors: unknown[] = [];
public handle(error: unknown): void {
// ADD error to context if necessary
this.integrationsRequestErrors.push(error);
}
}
export const ErrorSwallower = (options: {
serviceImplementation: string;
defaultValue: unknown;
errorMessage?: string;
}): MethodDecorator => {
const { defaultValue, integration } = options;
const Injector = Inject(ExceptionsHandler);
return (target: object, _propertyKey: string, descriptor: PropertyDescriptor) => {
Injector(target, 'exceptionsHandler');
const originalMethod = descriptor.value;
descriptor.value = function (...args: unknown[]) {
const exceptionHandler = this.experiment as ExceptionsHandler;
try {
const result = originalMethod.apply(this, args);
if (result amp;amp; result instanceof Promise) {
return result.catch((error: unknown) => {
exceptionHandler.handle({ error, integration });
return defaultValue;
});
}
return resu<
} catch (error) {
exceptionHandler.handle({ error, integration });
return defaultValue;
}
};
};
};
и вот приведенный выше код приведен в действие:
@Injectable()
export class ExampleService {
@ErrorSwallower({ serviceImplementation: 'ExampleClass', defaultValue: [] })
private async getSomeData(args: IGetSomeDataArgs): Promise<ISomeData[]> {
throw new Error('Oops');
}
}