typescript 在 Angular 4 中使用权限的最佳方式是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/45671520/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 04:49:03  来源:igfitidea点击:

What's the best way to work with permissions in Angular 4?

angulartypescript

提问by Gregor Doroschenko

In my Angular 4 project I would like to work with permissions, which I get from an API. Permissions are saved as array with ids. Some single elements like user or blog post have property with allowed permissions, which allow or not allow actions like edit or delete, as array with ids.

在我的 Angular 4 项目中,我想使用从 API 获得的权限。权限保存为带有 id 的数组。某些单个元素(例如用户或博客文章)具有允许权限的属性,这些属性允许或不允许编辑或删除等操作,作为带有 id 的数组。

What's the best way to check and to handle permissions in Angular 4 projects? Has Angular some out of the bos solutions for permissions handling? Can somebody give me ideas for realization of permissions handling, if Angular doesn't have some out of the box solution?

在 Angular 4 项目中检查和处理权限的最佳方法是什么?Angular 是否有一些用于权限处理的 bos 解决方案?如果 Angular 没有一些开箱即用的解决方案,有人可以给我实现权限处理的想法吗?

回答by federico scamuzzi

like Rahul comment says the one solution out of the box is more likely what you want are Guard..

就像 Rahul 评论说,开箱即用的一种解决方案更有可能是您想要的Guard......

Remember guard are only for ROUTING .. so only to check if a user can access a route or not .. but not to display single element in a component based on roles or whatever .. for that i suggest to you to use *ngIfor show to render/display or not some UI elements ...

请记住,守卫仅用于 ROUTING .. 所以仅用于检查用户是否可以访问路由 .. 而不是基于角色或其他内容在组件中显示单个元素 .. 为此,我建议您使用*ngIf或显示渲染/显示或不显示某些 UI 元素...

For one Guard based on Roles (not only if use is auth or not) ..you can do something like:

对于一个基于角色的 Guard(不仅在使用是否为 auth 时)..您可以执行以下操作:

import { Injectable } from "@angular/core";
import { AuthService, CurrentUserService } from "app/shared/services";
import { Router, RouterStateSnapshot, ActivatedRouteSnapshot, CanActivate } from "@angular/router";
import { AspNetUsersDTO } from "app/shared/models";
import { Observable } from "rxjs/Rx";

@Injectable()
export class RoleGuard implements CanActivate {

    constructor(private authService: AuthService,
        private _currentUser: CurrentUserService,
        private router: Router) {
    }

    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
        return new Promise<boolean>((resolve, reject) => {

            if (!this.authService.isLoggedIn()) {
                resolve(false);
                return;
            }


            var currentUser: AspNetUsersDTO = new AspNetUsersDTO();

            this._currentUser.GetCurrentUser().then((resp) => {
                currentUser = resp;
                let userRole = currentUser.roles && currentUser.roles.length > 0 ? currentUser.roles[0].toUpperCase() : '';
                let roles = route && route.data["roles"] && route.data["roles"].length > 0 ? route.data["roles"].map(xx => xx.toUpperCase()) : null;

                if (roles == null || roles.indexOf(userRole) != -1) resolve(true);
                else {
                    resolve(false);
                    this.router.navigate(['login']);
                }

            }).catch((err) => {
                reject(err);
                this.router.navigate(['login']);
            });
        });

    }

    canActivateChild(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {

        return new Promise<boolean>((resolve, reject) => {

            if (!this.authService.isLoggedIn()) {
                resolve(false);
                return;
            }


            var currentUser: AspNetUsersDTO = new AspNetUsersDTO();

            this._currentUser.GetCurrentUser().then((resp) => {
                currentUser = resp;
                let userRole = currentUser.roles && currentUser.roles.length > 0 ? currentUser.roles[0].toUpperCase() : '';
                let roles = route && route.data["roles"] && route.data["roles"].length > 0 ? route.data["roles"].map(xx => xx.toUpperCase()) : null;

                if (roles == null || roles.indexOf(userRole) != -1) resolve(true);
                else {
                    resolve(false);
                    this.router.navigate(['login']);
                }

            }).catch((err) => {
                reject(err);
                this.router.navigate(['login']);
            });
        });

    }
}

And then you can use in your routing like:

然后你可以在你的路由中使用,如:

{
        path: 'awards-team',
        component: AwardsTeamComponent,
        canActivateChild: [RoleGuard],
        children: [
          {
            path: 'admin',

            component: TeamComponentsAdminComponent,
            data: { roles: ['super-admin', 'admin', 'utente'] }
          },
          {
            path: 'user',

            component: TeamComponentsUserComponent,
            data: { roles: ['utente'] }
          }
        ]
      }

回答by alexKhymenko

You can try to use ngx-permissionslibrary for controlling of permissions in your angular application. The benefits it will remove elements from DOM. Example of loading permissions

您可以尝试使用ngx-permissions库来控制 angular 应用程序中的权限。它的好处是从 DOM 中删除元素。加载权限示例

import { Component, OnInit } from '@angular/core';
import { NgxPermissionsService } from 'ngx-permissions';
import { HttpClient } from '@angular/common/http';
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {

  title = 'app';

   constructor(private permissionsService: NgxPermissionsService,
               private http: HttpClient) {}

  ngOnInit(): void {
    const perm = ["ADMIN", "EDITOR"];

    this.permissionsService.loadPermissions(perm);

     this.http.get('url').subscribe((permissions) => {
       //const perm = ["ADMIN", "EDITOR"]; example of permissions
       this.permissionsService.loadPermissions(permissions);
    })
  }
}

Usage in templates

在模板中的使用

<ng-template [ngxPermissionsOnly]="['ADMIN']" (permissionsAuthorized)="yourCustomAuthorizedFunction()" (permissionsUnauthorized)="yourCustomAuthorizedFunction()">
    <div>You can see this text congrats</div>
 </ng-template>
<div *ngxPermissionsOnly="['ADMIN', 'GUEST']">
    <div>You can see this text congrats</div>
</div>

 <div *ngxPermissionsExcept="['ADMIN', 'JOHNY']">
   <div>All will see it except admin and Johny</div>
 </div>

回答by IZI

From my personal point of view, get permission from API is optimal solution for user rights. In addition to checking permission by using canActivateattribute in Router, I like to use checking in navigation interceptor. Because it will keep the url when checking incorrect permissions instead of url localhost:42000/#/.../permission-denied

从我个人的角度来看,获得 API 许可是用户权限的最佳解决方案。除了canActivate在路由器中使用属性检查权限之外,我喜欢使用导航拦截器中的检查。因为它会在检查不正确的权限时保留 url 而不是 url localhost:42000/#/.../permission-denied

Here is my code:

这是我的代码:

In template

在模板中

  <ng-template [ngIf]="!loading" [ngIfElse]="loadingView">
    <router-outlet *ngIf="canView"></router-outlet>
    <app-permission-denied *ngIf="!canView"></app-permission-denied>
  </ng-template>
  <app-loading #loadingView></app-loading>

In component

在组件中

import { Component, OnInit} from '@angular/core';
import {
  Router,
  // import as RouterEvent to avoid confusion with the DOM Event
  Event as RouterEvent,
  NavigationStart,
  NavigationEnd,
  NavigationCancel,
  NavigationError
} from '@angular/router'
import { Title } from '@angular/platform-browser';
import { DataService } from '../core/service/data.service';
import { NotificationService } from '../core/service/notification.service';

@Component({
  selector: 'app-main',
  templateUrl: './main.component.html',
  styleUrls: ['./main.component.css']
})
export class MainComponent implements OnInit{

  // Sets initial value on first load
  loading: boolean = true;
  canView: boolean = false;
  haveErr: boolean = false;

  constructor(private renderer: Renderer2,
    private router: Router,
    private _dataService: DataService,
    private titleService: Title,
    private _notificationService: NotificationService) {   
    this.router.events.subscribe((event: RouterEvent) => {
      this.navigationInterceptor(event)
    })
  }

  ngOnInit() { }

  navigationInterceptor(event: RouterEvent): void {
    if (event instanceof NavigationStart) {
      this.loading = true;
      this.canView = false;
    }
    if (event instanceof NavigationEnd) {

      //get permission user by pass function ID here...
      let functionId = this.getDataRouter(this.router, "function");

      if (functionId != null) {
        this._dataService.get('your_api_to_check_permission_with_functionId' + functionId).subscribe(
          (data) => {
            if (data && data.CanRead) {
              this.canView = true;
              let title = this.getDataRouter(this.router, "title");
              this.titleService.setTitle(title);
            } else {
              this.canView = false;
              this.titleService.setTitle('Permission denied');
            }
            this.loading = false
          }, (err) => {
            this._dataService.handleError(err);
          });
      } else {
        this.loading = false;
        this.canView = true;
        this._notificationService.printErrorMessage('Dev: please provide function Id to check permission');
      }

    }

    // Set loading state to false in both of the below events to hide in case a request fails
    if (event instanceof NavigationCancel) {
      this.loading = false
    }
    if (event instanceof NavigationError) {
      this.loading = false
    }
  }

  getDataRouter(router, name) {
    var root = router.routerState.snapshot.root;
    while (root) {
      if (root.children && root.children.length) {
        root = root.children[0];
      } else if (root.data && root.data[name]) {
        return root.data[name];
      } else {
        break;
      }
    }
    return null;
  }
}

In router module

在路由器模块中

const mainRoutes: Routes = [
      { path: 'user', loadChildren: './system/user/user.module#UserModule', data: { function: "USER" } },

      { path: 'function', loadChildren: './system/function/function.module#FunctionModule', data: { function: "FUNCTION" } }
    ]

回答by Krishna Ganeriwal

The best way I would suggest you do it is using the Router Guardthat Angular provides.

我建议您这样做的最佳方法是使用Angular 提供的Router Guard

The following links could help get you started:

以下链接可以帮助您入门:

router guard alligator

路由器保护鳄鱼

Router Guard Medium

路由器保护介质