You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular路由异常:从PageNotFound页返回时跳转到登录页

Angular路由异常修复:从404页面返回时被重定向到登录页的问题解决

问题核心

进入PageNotFoundComponent后点击返回上一页,触发AuthenticationGuard的canActivate()返回false,导致页面被强制重定向到登录页,但用户实际处于已登录状态。

根本原因

  1. 同步判断的时机问题:AuthenticationGuard中用类属性currentUser存储用户信息,而组件初始化时订阅currentUser$是异步操作,当路由守卫触发时,currentUser可能还未被赋值,或者在从404页面返回的场景下,currentUser的值未及时同步最新状态。
  2. 错误的流取值方式:AuthorizationGuard中使用currentUser$.getValue()直接获取流的值,若流尚未发射数据会导致异常,且无法保证拿到最新的用户状态。
  3. 角色匹配逻辑bug:matchesRole方法中,判断allOf条件时错误使用了routeRoleList.oneOf.every,应该用routeRoleList.allOf.every。

修复方案

1. 重构AuthenticationGuard,基于异步流判断用户状态

移除类属性存储用户信息,直接订阅authService.currentUser$流,确保每次守卫判断都获取最新的用户状态,同时返回Observable<boolean | UrlTree>符合Angular守卫的规范。

修改后的代码:

@Injectable({
  providedIn: 'root',
})
export class AuthenticationGuard {
  constructor(
    private authService: AuthService,
    private router: Router,
    @Inject(APP_CONFIG) private appConfig: AppEnvConfiguration
  ) {}

  canActivate(): Observable<boolean | UrlTree> {
    if (this.appConfig.skipLogin) {
      return of(true);
    }

    return this.authService.currentUser$.pipe(
      take(1), // 仅取一次最新的用户状态
      map(user => {
        if (user && user.isAuthenticated()) {
          return true;
        }
        // 返回UrlTree替代直接navigate,更符合守卫的设计逻辑
        return this.router.createUrlTree(['/auth']);
      })
    );
  }
}

2. 修复AuthorizationGuard的异步判断逻辑

将同步取值改为订阅流的方式,避免getValue()带来的潜在异常,同时统一返回Observable<boolean | UrlTree>。

修改后的代码:

@Injectable({
  providedIn: 'root',
})
export class AuthorizationGuard {
  constructor(
    private authService: AuthService,
    private router: Router,
    @Inject(APP_CONFIG) private appConfig: AppEnvConfiguration
  ) {}

  canActivateChild(
    route: ActivatedRouteSnapshot
  ): Observable<boolean | UrlTree> {
    if (this.appConfig.skipLogin) {
      return of(true);
    }

    return this.authService.currentUser$.pipe(
      take(1),
      map(currentUser => {
        if (!currentUser || !currentUser.authenticatedAndAuthorized) {
          return this.router.createUrlTree(['forbidden']);
        }

        const routeRoleList: RouteRule = route?.data?.['roleList'] || null;
        if (!routeRoleList || this.matchesRole(routeRoleList, currentUser)) {
          return true;
        } else {
          return this.router.createUrlTree(['forbidden']);
        }
      })
    );
  }

  matchesRole(routeRoleList: RouteRule, user: OPLUser | null): boolean {
    let match = true;

    if (routeRoleList.oneOf?.length) {
      match = routeRoleList.oneOf.some(role => user?.hasRole(role));
    }

    if (routeRoleList.allOf?.length) {
      // 修复原代码的bug:使用allOf数组进行every判断
      match = routeRoleList.allOf.every(role => user?.hasRole(role));
    }

    return match;
  }
}

3. 验证路由配置的合理性

当前路由配置中,PageNotFoundComponent(path: '**')未添加任何守卫,这是正确的,确保未登录用户也能访问404页面。返回时触发的是之前需要认证的路由,此时重构后的守卫会正确获取最新用户状态,避免误判。

内容的提问来源于stack exchange,提问作者sieniu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 20:06:01