我有一个实现CanActivate的AuthGuard,它根据一些自定义逻辑返回true或false:
import { Injectable } from '@angular/core';
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { AuthService } from '../services/auth.service';
import { UserTypes } from '../model/user-type';
@Injectable()
export class AuthGuard implements CanActivate {
constructor(
private router: Router,
private authService: AuthService
) {
}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
const allowedRoles = route.data['allowedRoles'] as Array<UserTypes>;
if (!allowedRoles) {
// All users allowed
return true;
}
// Check user's role against the allowed roles defined
const canActivate = (allowedRoles.indexOf(this.authService.userData.UserTypeId) !== -1);
if (!canActivate) {
this.router.navigate(['/portal']);
}
return canActivate;
}
}
我需要两个canActivate
参数(route: ActivatedRouteSnapshot, state: RouterStateSnapshot
)进行处理(并非所有代码都显示)。
我的路线定义了一些路线数据,告诉我哪些用户类型可以访问路线。当尝试访问路线时,这一切都非常好:
const routes: Routes = [
{
path: '',
component: PortalLayoutComponent,
children: [
{
path: '',
canActivate: [AuthGuard],
component: PortalDashboardComponent
},
{
path: 'customers',
canActivate: [AuthGuard],
data: { allowedRoles: [UserTypes.Admin] },
children: [
{ path: '', component: PortalCustomerListComponent }
]
}
]
}
];
如果 - 对于任何给定的链接 - canActivate返回false,我想隐藏模板中的链接。我不知道如何实现这一目标。这是模板中的典型链接:
<a [routerLink]="['customers']">List Customers</a>
如何在不重复我已加入AuthGuard的用户类型逻辑的情况下如何禁用此功能?我试图将AuthGuard注入到我的组件中,但我无法弄清楚如何提供canActivate所需的两个参数?这是一个示例组件,其中包含一些目前正在努力工作的测试代码:
import { Component } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Constants } from '../../app.constants';
import { AuthGuard } from '../../guards/auth.guard';
@Component({
templateUrl: './portal-dashboard.component.html',
styleUrls: ['./portal-dashboard.component.scss']
})
export class PortalDashboardComponent {
constructor(
private authGuard: AuthGuard,
private activatedRoute: ActivatedRoute,
private router: Router
) { }
public get canActivateLink(targetUrl: string): boolean {
**// TODO: Use targetLink here to get user role rules from the route data?**
return this.authGuard.canActivate(this.activatedRoute.snapshot, this.router.routerState.snapshot);
}
}
如果我能够完成上述工作,我只需在模板中执行以下操作(不是100%DRY,而是将重复角色逻辑添加到控制器中以用于每个链接):
<a [routerLink]="['customers']" *ngIf="canActivateLink('customers')">List Customers</a>
更新
感谢Yordan,我设法让这项工作成为指令。但是,我仍然有完全相同的问题,因为我无法找到一种简单的方法来获取特定URL的路由信息(即路由数据)。这是我到目前为止所得到的:
import { Input, OnInit, Directive, ViewContainerRef, TemplateRef } from '@angular/core';
import { LocationStrategy } from '@angular/common';
import { Router, ActivatedRoute, UrlTree } from '@angular/router';
import { AuthService, AuthState } from '../../services/auth.service';
import { UserTypes } from '../../model/user-type';
@Directive({
selector: '[hiddenIfUnauthorised]'
})
export class HiddenIfUnauthorisedDirective implements OnInit {
private commands: any[] = [];
constructor(
private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef,
private locationStrategy: LocationStrategy,
private router: Router,
private route: ActivatedRoute,
private auth: AuthService
) { }
@Input()
set hiddenIfUnauthorised(commands: any[] | string) {
if (commands != null) {
this.commands = Array.isArray(commands) ? commands : [commands];
} else {
this.commands = [];
}
console.log(this.commands);
}
get urlTree(): UrlTree {
// TODO: Mimic the rest of the relevant options as per the RouterLink source
return this.router.createUrlTree(this.commands, {
relativeTo: this.route
});
}
public ngOnInit() {
const urlTree = this.urlTree;
const sUrl = this.router.serializeUrl(urlTree);
const url = this.locationStrategy.prepareExternalUrl(sUrl);
// TODO: I need to generate an ActivatedRoute object for the "url" created above
// so I can get 'allowedRoles' from route data - or get it some other way.
// Are there any helper methods anywhere?
const targetRoute = this.route;
const userTypes = targetRoute.data['allowedRoles'] as Array<UserTypes>;
const authState = this.auth.getAuthState(userTypes);
if (authState !== AuthState.Authorised) {
// Not authorised, remove the DOM container
this.viewContainer.clear();
} else {
// Show the DOM container
this.viewContainer.createEmbeddedView(this.templateRef);
}
}
}
这是在我的模块中注册的,然后在模板中使用如下:
<div *hiddenIfUnauthorised="['customers']">
Secure Content!
</div>
如果有人有任何想法,还在寻找解决方案吗?
答案 0 :(得分:0)
这是我的意思的快速代码
import { Directive, TemplateRef, ViewContainerRef } from '@angular/core';
@Directive({ selector: '[permission]' })
export class IfDirective {
constructor(
private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef,
private auth: AuthService
) { }
@Input() permission: string;
public ngOnInit() {
if(this.auth.hasPermission) {
// If condition is true add template to DOM
this.viewContainer.createEmbeddedView(this.templateRef);
} else {
// Else remove template from DOM
this.viewContainer.clear();
}
}
}
被修改