Why interacting of two guards leads to infinite redirection loop in Angular 18?

Discussão em 'Angular' iniciado por ADEXITUM, Outubro 27, 2024.

  1. ADEXITUM

    ADEXITUM Guest

    I've got routes '/' and '/auth'. The logic is that NOT logged in users can access ONLY /auth page, while logged in users CAN'T access it.

    So, I've made two guards and for some reason I get infinite loop between them.

    I've set up routes like this:

    app.routes.ts:

    {
    path: 'auth',
    canActivate: [OnlyUnauthorizedGuard],
    children: [
    { path: '', component: AuthComponent, pathMatch: 'full' },
    { path: 'login', component: LoginComponent },
    { path: 'register', component: RegisterComponent },
    ]
    },
    {
    path: '',
    data: {
    allowedRoleIDs: [UserRole.Customer, UserRole.Owner, UserRole.Admin, UserRole.Root]
    },
    canActivate: [RoleGuard],
    component: MainComponent,
    },


    My guards are:

    role.guard.ts:

    export class RoleGuard implements CanActivate {
    constructor(private authService: AuthService, private router: Router) { }

    canActivate(route: ActivatedRouteSnapshot): Observable<boolean> {
    console.log('Triggered RoleGuard');
    const allowedRoles = route.data['allowedRoleIDs'] as number[];

    return this.authService.user$.pipe(
    map(user => {
    console.log('user', user);
    if (user === null) {
    console.log('Redirecting to /auth since user is null');
    this.router.navigate(['/auth']);
    return false;
    }

    if (user && !allowedRoles.includes(user.roleID)) {
    console.log('Redirecting to /404');
    this.router.navigate(['/404']);
    return false;
    }

    return true;
    })
    );
    }
    }`


    onlyUnauthorized.guard.ts:

    export class OnlyUnauthorizedGuard implements CanActivate {
    constructor(private authService: AuthService, private router: Router) {}

    canActivate(): Observable<boolean> {
    console.log('Triggered OnlyUnauthorizedGuard');
    return this.authService.user$.pipe(
    take(1),
    map(user => {
    console.log('user ', user);

    if (user) {
    console.log('User is logged in so redirecting to /');
    this.router.navigate(['/']);
    return false;
    }

    console.log('Allowed');
    return true;
    })
    );
    }
    }
    `


    How I get user data:

    auth.service.ts:

    export class AuthService {
    private _userSubject = new BehaviorSubject<User | null>(null);
    user$ = this._userSubject.asObservable();
    constructor(
    private http: HttpClient
    ) {
    this.loadUser();
    }

    private loadUser() {
    this._loadingSubject.next(true);
    this.http.get<User>('/auth/getUser').pipe(
    tap(user => {
    this._userSubject.next(user)
    console.log(user)
    }),
    catchError(() => {
    this._userSubject.next(null);
    return of(null);
    }),
    finalize(() => this._loadingSubject.next(false))
    ).subscribe();
    }

    get user() {
    return this._userSubject.value;
    }
    }`


    On a page I've got strange error: PM [vite] Internal server error: Page /auth/getUser did not render in 30 seconds.

    I don't see a request to /auth/getUser on a network tab in browser.

    There are such logs in Docker when access /auth page (there are no logs on a console tab in browser) :

    `
    2024-10-28 00:26:06 Triggered RoleGuard
    2024-10-28 00:26:06 user null
    2024-10-28 00:26:06 Redirecting to /auth since user is null
    2024-10-28 00:26:06 Triggered OnlyUnauthorizedGuard
    2024-10-28 00:26:06 user null
    2024-10-28 00:26:06 Allowed
    2024-10-28 00:26:06 Triggered RoleGuard
    ...`


    It seems that for some reason even if OnlyUnauthorizedGuard returns true a redirect to / happens.

    Continue reading...

Compartilhe esta Página