Angular2:如何使用路由(重新检查canActivate)“重新加载”页面?

13

我有带有canActivate: [AuthGuard]和验证的路由器在AuthGuard内部。

如何强制检查同一路由器URL中的canActivate

例如:当前路由为/admin,我收到了像会话过期这样的事件。我在AuthGuard中进行了会话检查,但只有当我执行.navigate(...)时才会激活此检查。如何强制在同一位置运行canActivate

我已尝试:this.router.navigate([this.router.url]);但是Angular检查相同位置并什么都不做。

p.s. 当我收到会话过期事件时,我可以定位到“登录页面”或其他页面,但我所有的重定向都在AuthGuard中,并且我不想在所有其他事件中重复相同的重定向,我只需要类似于location.reload()但在Angular2路由中。

主要问题可以描述为:如何强制在当前位置重新运行canActivate保护程序?

2个回答

7

我的临时解决方案:

auth.service.ts

import { Injectable, Injector } from '@angular/core';
import { ActivatedRoute, Router, RouterStateSnapshot } from '@angular/router';

@Injectable()
export class AuthService {

  constructor(private route: ActivatedRoute,
              private router: Router,
              private injector: Injector) {
    this.forceRunAuthGuard();
  }

  // Dirty hack for angular2 routing recheck
  private forceRunAuthGuard() {
    if (this.route.root.children.length) {
      // gets current route
      const curr_route = this.route.root.children[ '0' ];
      // gets first guard class
      const AuthGuard = curr_route.snapshot.routeConfig.canActivate[ '0' ];
      // injects guard
      const authGuard = this.injector.get(AuthGuard);
      // makes custom RouterStateSnapshot object
      const routerStateSnapshot: RouterStateSnapshot = Object.assign({}, curr_route.snapshot, { url: this.router.url });
      // runs canActivate
      authGuard.canActivate(curr_route.snapshot, routerStateSnapshot);
    }
  }

}

app.routes.ts

  { path: 'faq', canActivate: [ AuthGuard ], component: FaqComponent },
  { path: 'about', canActivate: [ AuthGuard ], component: AboutUsComponent },
  { path: 'upgrade', canActivate: [ AuthGuard ], component: UpgradeComponent },

这段代码再次运行了 AuthGuard


1
很棒的解决方案,完美运作!我做了一些其他的研究,你的是我找到的最好的。你有找到改进这个的方法吗?虽然它不需要改进,只是好奇。 - Julian Fraser
@JulianFraser 不,我一直在生产环境中使用它。 - mixalbl4
今天我遇到了这个问题。我也做了很多谷歌搜索,这个解决方案是我能找到的最好的。 (我还发现了这个:https://dev59.com/WKbja4cB1Zd3GeqPag4R,但对我来说太麻烦了)。我可能会对您的解决方案进行一些更改,即检查所有守卫,但就我个人而言,我从未需要超过一个守卫,所以... 耸耸肩 - Ben

0

不幸的是,@mixalbl4的答案今天仍然相关,但我想给出一个更通用的方法,下面的代码将适用于任何AuthGuard:

import { Injectable, Injector } from "@angular/core";
import { ActivatedRoute, CanActivate, CanActivateChild, Router, RouterStateSnapshot, UrlTree } from "@angular/router";
import { concat, concatMap, from, isObservable, last, Observable, of, skip, takeWhile } from "rxjs";

@Injectable()
export class AuthService{
    protected routeSnapshot: RouterStateSnapshot;

    constructor(
        protected route: ActivatedRoute,
        protected injector: Injector,
        protected router: Router){

        this.routeSnapshot = Object.assign({}, this.route.snapshot, { url: this.router.url });
    }

    public checkActivation(){
        this.checkRouteActivation(this.route).subscribe(a => {
            if(a !== true){
                if(a === false)
                    a = this.router.parseUrl("DEFAULT_ROUTE"); // Route to redirect to on activation fail, if not specified by guard

                this.router.navigateByUrl(a as UrlTree);
            }
        });
    }

    private checkRouteActivation(route: ActivatedRoute):Observable<boolean | UrlTree>{
        let conditions:Observable<boolean | UrlTree>[] = [];

        // Check own activation
        if(route.routeConfig){
            if(route.routeConfig.canActivate?.length ?? 0 > 0)
                conditions.push(...route.routeConfig.canActivate!.map(a => this.validateGuard(a, route, false)));

            if(route.routeConfig.canActivateChild?.length ?? 0 > 0)
                conditions.push(...route.routeConfig.canActivateChild!.map(ac => this.validateGuard(ac, route, true)));
        }

        // Add last true (if does not have any activations or parents)
        if(conditions.length == 0)
            conditions.push(of(true));

        let ownObservable = concat(...conditions).pipe(takeWhile(v => v === true, true), last());

        // Validate parent if present
        if(route.parent)
            return this.checkRouteActivation(route.parent).pipe(concatMap(v => v === true ?
                ownObservable :
                of(v)));
        else
            return ownObservable;
    }

    private validateGuard(guardToken: any, route: ActivatedRoute, child:boolean):Observable<boolean | UrlTree>{
        var guard: (CanActivate & CanActivateChild) = this.injector.get(guardToken);
        
        let result:Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree;
        if(!child)
            result = guard.canActivate(route.snapshot, this.routeSnapshot);
        else
            result = guard.canActivateChild(route.snapshot, this.routeSnapshot);

        if(isObservable(result))
            return result;
        else if(typeof (result as any)?.then === 'function') // check if is promise
            return from(result as Promise<boolean | UrlTree>);
        else
            return of(result as boolean | UrlTree);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接