Guardy określają, czy żądanie może przejść do handlera trasy — to dedykowany mechanizm NestJS do autoryzacji (oraz często kontroli uwierzytelniania). Guard zwraca true, aby zezwolić na żądanie, lub false/wyrzuca wyjątek, aby je zablokować.
Guardy określają, czy żądanie może przejść do handlera trasy — to dedykowany mechanizm NestJS do autoryzacji (oraz często kontroli uwierzytelniania). Guard zwraca true, aby zezwolić na żądanie, lub false/wyrzuca wyjątek, aby je zablokować.
@Injectable()
export class AuthGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
const request = context.switchToHttp().getRequest();
return !!request.headers.authorization; // true = allow, false = block (403)
}
}
Guard implementuje canActivate(), które zwraca boolean (lub Promise/Observable z nim). Zwrócenie false blokuje żądanie z kodem 403; możesz również wyrzucić konkretny wyjątek (np. UnauthorizedException).
@UseGuards(AuthGuard) // on a single route
@Get("profile")
getProfile() {}
@UseGuards(AuthGuard) // on a whole controller (all routes)
@Controller("admin")
export class AdminController {}
app.useGlobalGuards(new AuthGuard()); // globally (all routes)
Guardy mogą być stosowane na poziomie metody, kontrolera lub globalnie.
@Injectable()
export class JwtAuthGuard implements CanActivate {
constructor(private jwtService: JwtService) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest();
const token = request.headers.authorization?.split(" ")[1];
if (!token) throw new UnauthorizedException();
try {
request.user = await this.jwtService.verifyAsync(token); // attach the user
return true;
} catch {
throw new UnauthorizedException("Invalid token");
}
}
}
// a @Roles decorator stores required roles as metadata
@Roles("admin")
@Get("users")
listUsers() {}
// the RolesGuard reads the metadata and checks the user's roles
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(ctx: ExecutionContext): boolean {
const roles = this.reflector.get<string[]>("roles", ctx.getHandler());
const { user } = ctx.switchToHttp().getRequest();
return roles.some(role => user.roles?.includes(role)); // allow if the user has a required role
}
}
Łączenie dekoratora @Roles() (metadane) z guardem, który go czyta (poprzez Reflector), jest standardowym wzorcem kontroli dostępu opartej na rolach.
The ExecutionContext gives guards rich info (the handler, class, request) — more
than plain middleware — which is why guards (not middleware) are the right place
for authorization decisions.
Guardy to dedykowany, idiomatyczny mechanizm NestJS do autoryzacji — kontrolowania, które żądania mogą osiągnąć handlery na podstawie uwierzytelniania i uprawnień.
Zrozumienie ich jest niezbędne, ponieważ praktycznie każda rzeczywista aplikacja musi chronić trasy (wymagać logowania, sprawdzać role/uprawnienia), a guardy są właściwym narzędziem do tego (znacznie czystsze niż wkładanie logiki auth do middleware lub do każdego handlera).
Standardowe wzorce — guard JWT/auth, który weryfikuje poświadczenia i dołącza użytkownika do żądania, oraz guardy oparte na rolach łączące dekorator @Roles() z guardem czytającym Reflector do RBAC — są fundamentalne dla zabezpieczania API NestJS.
Dostęp guardów do bogatego ExecutionContext (wiedza o docelowym handlerze, klasie i żądaniu) jest dokładnie tym, co czyni je odpowiednimi do decyzji autoryzacyjnych, które middleware nie może czysto podejmować.
Wiedzenie, jak pisać, stosować (na poziomie metody/kontrolera/globalnym) i łączyć guardy z dekoratorami metadanych jest kluczową wiedzą do budowania bezpiecznych aplikacji NestJS i częstym, architektonicznie ważnym tematem w frameworku.