javascript - När man ska använda guards och när man ska använda middlewares i NestJs
Jag vill skapa en NestJs-app och vill ha en middleware som validerar token i förfrågningsobjektet och en autentiseringsvakt som validerar användaren i token-payloaden.
Genom att dela på detta hoppades jag på en tydlig separation. Först min middleware
@Injectable()
export class TokenMiddleware implements NestMiddleware {
use(req: any, res: Response, next: NextFunction) {
try {
const headers: IncomingHttpHeaders = req.headers;
const authorization: string = headers.authorization;
const bearerToken: string[] = authorization.split(' ');
const token: string = bearerToken[1];
// !! Check if token was invalidated !!
req.token = token;
req.tokenPayload = verifyToken(token);
next();
} catch (error) {
throw new UnauthorizedException();
}
}
}
Det validerar endast token och utökar begäran med den kodade token och dess nyttolast. Min autentiseringsskydd
@Injectable()
export class AuthenticationGuard implements CanActivate {
constructor(private readonly usersService: UsersService) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const request: any = context.switchToHttp().getRequest();
try {
const user: any = request.tokenPayload;
if (!user) {
throw new Error();
}
const findByIdDTO: FindByIdDTO = { id: user.id };
const existingUser: UserRO = await this.usersService.findById(findByIdDTO);
if (!existingUser) {
throw new Error();
}
// attach the user to the request object?
return true;
} catch (error) {
throw new UnauthorizedException();
}
}
}
Denna vakt kontrollerar om den angivna användaren i tokenpayload är en giltig användare. Om allt är korrekt, var bör jag fästa användaren på begäran-objektet? Så vitt jag vet kontrollerar vakten bara om något är korrekt. Men jag vill inte hålla all denna logik i token-mellanmjukvaran. Var kan jag fästa databas-användaren på begäran efter att valideringen i auth-vakten är klar?
Svar #1
Om du vill göra något liknande Passport kan du alltid koppla användaren till req.user, vilket ses som en ganska standardgrej i Node.JS-världen.
Sidofråga till dig: finns det något skäl till att inte ha två vakter som fungerar direkt efter varandra? Ha en vakt för att kontrollera att token finns och verkligen är en giltig token och en för att validera att användaren på token faktiskt är giltig. På så sätt använder du inte en middleware (som mest ingår för kompatibilitetens skull) och har fortfarande den separerade logiken.
Svar #2
Where can I attach the database user to the request after finishing the validation in the auth guard?Jag tror att Guard, som du märkte, bör kontrollera om den angivna användaren har rätt att använda den angivna metoden.
Beroende på dina behov kan du gå in på olika vägar:
1) använd passport och en strategi för att göra det du behöver (https://stackoverflow.com/a/57929429/4319037 Jag skrev redan några ord och rader om detta). Dessutom kommer det redan att täcka större delen av koden du måste använda för att extrahera token.
@Injectable()
export class HttpStrategy extends PassportStrategy(Strategy) {
constructor(private readonly authService: AuthService) {
super()
}
async validate(token: string) {
const user = await this.authService.findUserByToken(token);
if (!user) {
throw new UnauthorizedException();
}
return user;
}
}
2) använd Interceptor på controller-/metodnivå för att koppla användaren till den givna förfrågan (och kasta ett fel om token saknas); din Guard kommer redan att få user, så du kan validera om användaren har rätt roll/rättigheter för att köra metoden.
Vänligen låt mig veta om jag har missförstått vad du vill uppnå eller om du behöver fler detaljer om ett särskilt sätt, tack!
