javascript - Anpassade rutedekoratorer för NestJS
Jag har skapat några egna parameterdekorerare för mina rutter, men jag hittar ingen användbar dokumentation om hur man skapar en dekoratör för själva rutten. Det finns en del beskrivning om hur man kan paketera befintliga metoddekorerare tillsammans, vilket inte hjälper mig.
Det jag försöker uppnå är en enkel omfattningsvalidering. Omfattningarna är redan inställda i förfrågningskontexten. Det jag för närvarande har, baserat endast på TypeScript-dekoratorer, leder faktiskt ingenstans:
controller.ts
@RequiredScope(AuthScope.OWNER)
@Get('/some-route')
async get() {
...
}
required-scopes.ts
export function RequiredScope(...scopes: string[]) {
return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
console.log(`Validation of scopes '${scopes.join(',')}' for input '${RequestContext.getScopes().join(',')}'`)
if (!scopes.map(s => RequestContext.hasOneOfTheScopes(s)).find(valid => !valid)) {
throw new HttpException(`Missing at least one scope of '${scopes.join(',')}'`, HttpStatus.FORBIDDEN)
}
}
}
Problemet här är att min förfrågningskontext inte ens är tillgänglig eftersom min middleware som sätter upp min kontext inte har startat än. Förfrågan misslyckas omedelbart.
Kan någon visa mig åt rätt håll?
Svar #1
Som vänligt föreslagits av Khaled Mohamed (tack!), var det ganska enkelt att lösa detta med vakter och en bättre metod.
Skapa en dekoratör med de erforderliga omfattningarna som en parameter i scopes.decorator.ts:
export const Scopes = (...scopes: string[]) => SetMetadata('scopes', scopes)
Att sätta upp en guard som kontrollerar de angivna meta scopes och kollar om kravet uppfylls i scopes.guard.ts:
@Injectable()
export class ScopesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
const scopes = this.reflector.get<string[]>('scopes', context.getHandler())
if (!scopes || scopes.length === 0) return true
if (!scopes.map(s => RequestContext.hasOneOfTheScopes(s)).find(valid => !valid)) {
throw new HttpException(`Missing at least one scope of '${scopes.join(',')}'`, HttpStatus.FORBIDDEN)
}
return true
}
}
Aktivera vakten globalt i app.module.ts:
@Module({
imports: [...],
controllers: [...],
providers: [
{
provide: APP_GUARD,
useClass: ScopesGuard,
}
],
})
Att använda dekoratören vid routen i controller.ts:
@Scopes(AuthScope.OWNER)
@Get('/some-route')
async get() {
...
}
