这就是我最终的选择。由于没有任何“开箱即用”的方法来利用警卫做我想做的事情,我只是做了一个自定义指令。
关于这个解决方案,我要注意的一点是,我讨厌以下两件事(我最终会改变)。
-
如果你的守卫有任何做重定向的东西,你必须改变它,这样守卫只返回true/false。如果它重定向了Guard failure上的页面,那么该指令最终将重定向您,而不是隐藏元素
-
this._elementRef.nativeElement.style.display = hasAccess ? 'block' : 'none';
有一个更好的解决办法,而不是仅仅做一个简单的隐藏。它应该表现得像
*ngIf
它甚至根本不呈现元素,除非它的计算结果为true。
实施:
<div appGuard [guards]="myGuardsArray">Something you want to hide .... </div>
指令:
import { Directive, ElementRef, Injector, Input, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
@Directive({
selector: '[appGuard]'
})
export class GuardDirective implements OnInit {
@Input() guards: any[];
private readonly _elementRef: ElementRef;
private readonly _activatedRoute: ActivatedRoute;
private readonly _router: Router;
private readonly _injector: Injector;
constructor(_elementRef: ElementRef, _activatedRoute: ActivatedRoute, _router: Router,
_injector: Injector) {
this._elementRef = _elementRef;
this._activatedRoute = _activatedRoute;
this._router = _router;
this._injector = _injector;
}
async ngOnInit(): Promise<void> {
const canActivateInstances = this.guards.map( g => this._injector.get(g));
const results = await Promise.all(canActivateInstances.map( ca => ca.canActivate(this._activatedRoute.snapshot, this._router.routerState.snapshot)));
const hasAccess = results.find( r => !r) === false ? false : true;
this._elementRef.nativeElement.style.display = hasAccess ? 'block' : 'none';
}
}
更新
一个简单的解决方案来确定如何处理重定向:
async canActivate(
next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
const user = await this._meService.getCurrentUser();
const result = user && user.isUserAdminForCompany;
if (next.routeConfig && next.routeConfig.canActivate.find( r => r.name === 'NameOfGuard') && !result) {
window.location.href = `${environment.webRoot}/sign-in`;
}
return result;
}