为什么两个守卫的交互会导致 Angular 18 中的无限重定向循环?

问题描述 投票:0回答:1

我有路线 '/''/auth'。逻辑是未登录的用户只能访问 /auth 页面,而登录的用户无法访问它。

所以,我做了两个守卫,由于某种原因,我在它们之间得到了无限循环。

我已经设置了这样的路线:

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,
    },

我的守卫是:

角色.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;
          })
        );
      }
    }
`    

如何获取用户数据:

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;
  }
}`     

在页面上我遇到了奇怪的错误:

PM [vite] Internal server error: Page /auth/getUser did not render in 30 seconds.

我在浏览器的网络选项卡上没有看到对 /auth/getUser 的请求。

在 Docker 中访问 /auth 页面时有这样的日志(浏览器中的控制台选项卡上没有日志):

`
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
...`

似乎由于某种原因,即使OnlyUnauthorizedGuard返回true,也会发生重定向到/的情况。

angular single-page-application angular2-routing angular-router-guards
1个回答
0
投票

如果用户为null,并且访问根路径/,RoleGuard会重定向到/auth,然后一旦允许,它会尝试再次重定向回/,从而导致无限循环。

调整防护装置,防止形成环路。在两个守卫中使用 take(1) 以确保它们正确完成可观察链,然后确保在触发守卫之前加载用户。考虑将用户状态初始化为未定义,并在解析为 null 或用户对象后处理逻辑,并确保不直接在防护内部使用导航。相反,返回一个 URL 树。

角色卫士

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

    canActivate(route: ActivatedRouteSnapshot): Observable<boolean> | UrlTree {
        console.log('Triggered RoleGuard');
        const allowedRoles = route.data['allowedRoleIDs'] as number[];
    
        return this.authService.user$.pipe(
          take(1),
          map(user => {
            console.log('user', user);
            if (user === null) {
              return this.router.createUrlTree(['/auth']);
            }

            if (user && !allowedRoles.includes(user.roleID)) {
              return this.router.createUrlTree(['/404']);
            }

            return true;
          })
        );
    }
}

仅限未经授权的Guard

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

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

            if (user) {
              return this.router.createUrlTree(['/']);
            }

            return true;
          })
        );
      }
}

尝试添加加载状态以在获取用户数据时处理 UI 反馈。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.