From 04e5d4da5941c2085dd37d37380724940468eca7 Mon Sep 17 00:00:00 2001 From: Fahri Gedik Date: Tue, 25 Nov 2025 19:25:42 +0300 Subject: [PATCH] Add redirectUrl support to PermissionGuard PermissionGuard now supports redirecting to a specified URL when access is denied and a redirectUrl is provided in route data. Updated guard logic to use map instead of filter/tap, and added corresponding unit tests to verify redirect behavior. --- .../core/src/lib/guards/permission.guard.ts | 31 ++++++++++++++----- .../src/lib/tests/permission.guard.spec.ts | 17 ++++++++++ 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/guards/permission.guard.ts b/npm/ng-packs/packages/core/src/lib/guards/permission.guard.ts index 8d1e478864..3b77913d2e 100644 --- a/npm/ng-packs/packages/core/src/lib/guards/permission.guard.ts +++ b/npm/ng-packs/packages/core/src/lib/guards/permission.guard.ts @@ -4,10 +4,11 @@ import { CanActivateFn, Router, RouterStateSnapshot, + UrlTree, } from '@angular/router'; import { HttpErrorResponse } from '@angular/common/http'; import { Observable, of } from 'rxjs'; -import { filter, take, tap } from 'rxjs/operators'; +import { map, take } from 'rxjs/operators'; import { AuthService, IAbpGuard } from '../abstracts'; import { findRoute, getRoutePath } from '../utils/route-utils'; import { RoutesService, PermissionService, HttpErrorReporterService } from '../services'; @@ -25,7 +26,7 @@ export class PermissionGuard implements IAbpGuard { protected readonly permissionService = inject(PermissionService); protected readonly httpErrorReporter = inject(HttpErrorReporterService); - canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { + canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { let { requiredPolicy } = route.data || {}; if (!requiredPolicy) { @@ -38,12 +39,19 @@ export class PermissionGuard implements IAbpGuard { } return this.permissionService.getGrantedPolicy$(requiredPolicy).pipe( - filter(Boolean), take(1), - tap(access => { - if (!access && this.authService.isAuthenticated) { + map(access => { + if (access) return true; + + if (route.data?.['redirectUrl']) { + return this.router.parseUrl(route.data['redirectUrl']); + } + + if (this.authService.isAuthenticated) { this.httpErrorReporter.reportError({ status: 403 } as HttpErrorResponse); } + + return false; }), ); } @@ -77,12 +85,19 @@ export const permissionGuard: CanActivateFn = ( } return permissionService.getGrantedPolicy$(requiredPolicy).pipe( - filter(Boolean), take(1), - tap(access => { - if (!access && authService.isAuthenticated) { + map(access => { + if (access) return true; + + if (route.data?.['redirectUrl']) { + return router.parseUrl(route.data['redirectUrl']); + } + + if (authService.isAuthenticated) { httpErrorReporter.reportError({ status: 403 } as HttpErrorResponse); } + + return false; }), ); }; diff --git a/npm/ng-packs/packages/core/src/lib/tests/permission.guard.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/permission.guard.spec.ts index 1a0ae3e147..45f3b46d80 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/permission.guard.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/permission.guard.spec.ts @@ -39,6 +39,15 @@ describe('authGuard', () => { component: DummyComponent, canActivate: [permissionGuard], }, + { + path: 'redirect-test', + component: DummyComponent, + canActivate: [permissionGuard], + data: { + requiredPolicy: 'TestPolicy', + redirectUrl: '/zibzib', + }, + }, ]; beforeEach(() => { @@ -103,4 +112,12 @@ describe('authGuard', () => { await RouterTestingHarness.create('/zibzib'); expect(TestBed.inject(Router).url).toEqual('/zibzib'); }); + + it('should redirect to redirectUrl when the grantedPolicy is false and redirectUrl is provided', async () => { + permissionService.getGrantedPolicy$.andReturn(of(false)); + await RouterTestingHarness.create('/redirect-test'); + + expect(TestBed.inject(Router).url).toEqual('/zibzib'); + expect(httpErrorReporter.reportError).not.toHaveBeenCalled(); + }); });