【问题标题】:Angular - Hide Guarded Links in templateAngular - 在模板中隐藏受保护的链接
【发布时间】:2017-06-23 22:08:35
【问题描述】:

我有一个实现 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>

如果有人有任何想法,还在寻找解决方案吗?

【问题讨论】:

  • 我建议你做一个像 [authUrl] 这样的指令。在这些指令中实例化您的 Auth 服务并检查用户权限,基于此您可以显示/隐藏页面上的任何元素。
  • 尚未处理的指令 - 我现在会查找它们,谢谢。

标签: angular typescript roles angular-routing


【解决方案1】:

这是我的意思的快速代码

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();
    }
  }

}

编辑

【讨论】:

  • 很好的信息,但不是我想要的——我需要能够检索路由数据,以便检查当前用户的 userType 的链接。
  • 我现在不在电脑前,但我很确定你可以注入ActivatedRouter 并获取当前路线。你甚至可以像@Input()属性一样传递路由器
  • 如何使用这个指令?
猜你喜欢
  • 2012-12-15
  • 2015-03-26
  • 2013-12-10
  • 2012-03-13
  • 2014-01-23
  • 1970-01-01
  • 2016-04-06
  • 2012-12-08
  • 2015-01-19
相关资源
最近更新 更多