fix: Access-Token wird bei deaktivierten Usern sofort ungueltig

Bisher griff der isActive-Check nur auf Routen mit @RequirePermission.
Ein deaktivierter User mit gueltigem Token konnte Routen ohne
Permission-Decorator bis zum Token-Ablauf (bis zu 15 Min) weiter
erreichen. JwtAuthGuard prueft jetzt PermissionResolverService.isUserActive
auf jedem authentifizierten Request, ueber denselben 30s-Cache wie die
Permission-Aufloesung, also ohne zusaetzliche DB-Last.
This commit is contained in:
Nick Szaunig committed 2026-08-26 14:17:49 +02:00
1 parent 5a1015c4a0
commit adfbc2ab83
4 files changed
+191 -19

No files matched your search

@@ -1,15 +1,37 @@
import { ExecutionContext, Injectable } from '@nestjs/common';
import {
ExecutionContext,
Injectable,
UnauthorizedException,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport';
import { IS_PUBLIC_KEY } from '../decorators/public.decorator';
import { PermissionResolverService } from '../permissions/permission-resolver.service';
import { AuthenticatedUser } from '../types/authenticated-user';
interface RequestWithUser {
user?: AuthenticatedUser;
}
/**
* Enforces User.isActive on every authenticated request, not just ones
* gated by @RequirePermission. Without this, a deactivated user's
* still-valid access token would keep working on any route that carries no
* permission decorator until the token's own expiry (up to
* JWT_ACCESS_EXPIRES_IN). isUserActive shares PermissionsGuard's cache, so
* this check costs no extra query beyond what permission resolution already
* does.
*/
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
constructor(private readonly reflector: Reflector) {
constructor(
private readonly reflector: Reflector,
private readonly permissionResolver: PermissionResolverService,
) {
super();
}
canActivate(context: ExecutionContext) {
async canActivate(context: ExecutionContext): Promise<boolean> {
const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
context.getHandler(),
context.getClass(),
@@ -17,6 +39,15 @@ export class JwtAuthGuard extends AuthGuard('jwt') {
if (isPublic) {
return true;
}
return super.canActivate(context);
const authenticated = (await super.canActivate(context)) as boolean;
if (!authenticated) {
return false;
}
const request = context.switchToHttp().getRequest<RequestWithUser>();
const user = request.user;
if (!user || !(await this.permissionResolver.isUserActive(user.id))) {
throw new UnauthorizedException();
}
return true;
}
}