不幸的是,@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");
this.router.navigateByUrl(a as UrlTree);
}
});
}
private checkRouteActivation(route: ActivatedRoute):Observable<boolean | UrlTree>{
let conditions:Observable<boolean | UrlTree>[] = [];
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)));
}
if(conditions.length == 0)
conditions.push(of(true));
let ownObservable = concat(...conditions).pipe(takeWhile(v => v === true, true), last());
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')
return from(result as Promise<boolean | UrlTree>);
else
return of(result as boolean | UrlTree);
}
}