Angular pages use directives and routing guards for permission control

In various business systems, in order to ensure business and data security, in addition to requiring users to log in to operate, they also set their own access rights for different users according to different roles, including the rights of a certain page and the page. Permissions for specific elements.

This article records a commonly used permission management method for Angular pages.

1. Implementation principle

This method uses permission codes to mark the page routes and page elements that need permission control. When the user logs in to the system, the background returns all the permission codes that the corresponding user has permissions. Match to determine whether the user has access rights. For routing addresses, no permission will block access and redirect to the specified routing page (usually the login page), and for page elements, no permission will remove the corresponding element.

2. Examples

This example adds a login page ( http://localhost:4200/sign ) to the root route :

Then add two modules AModule and BModule, respectively add pages A1( http://localhost:4200/a/a1) , A2( http://localhost:4200/a/a2), B1( http://localhost:4200/a/a2) and B1( http ://localhost:4200/b/b1) , B2( http://localhost:4200/b/b2) . A1, A2, B1, B2 pages require login to access. Add four buttons to the A1 page, which require corresponding permission code permissions to access:

After a normal user logs in, only the normal user button can be seen on the A1 page, and the administrator button is invisible. After the administrator user logs in, all buttons are visible.

3. Implementation steps

3.1. Page routing tag permission code

Add route guards for each route in the route configuration files at all levels, add the acl attribute in the data parameter of the route, and specify the permission code of the mark:

  //AModule路由配置
  { path: 'a1', component: A1Component, canActivate: [AclGuard], data: { acl: "a.a1" } },
  { path: 'a2', component: A2Component, canActivate: [AclGuard], data: { acl: "a.a2" } },
  //BModule路由配置
  { path: 'b1', component: B1Component, canActivate: [AclGuard], data: { acl: "b.b1" } },
  { path: 'b2', component: B2Component, canActivate: [AclGuard], data: { acl: "b.b2" } },

3.2. Page element tag permission code

在html模板中,在想要进行权限控制的页面元素上添加权限控制指令([acl]),标记对应的权限码:

 <button [acl]="'a.a1.user.btn1'">普通用户按钮1</button>
 <button [acl]="'a.a1.admin.btn1'">管理员按钮1</button>
 <button [acl]="'a.a1.user.btn2'">普通用户按钮2</button>
 <button [acl]="'a.a1.admin.btn2'">管理员按钮2</button>

3.3、路由守卫检查权限

在路由守卫AclGuard中针对路由配置data参数中的权限码进行权限检查,拦截没有权限的访问:

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | Observable<boolean> | Promise<boolean> {
    let data: any = { acl: "anonymous" }; 
    Object.assign(data, route.data);
    if (this.acl.isAclAuthorized(data.acl)) {
      return true;
    } else {
      alert("没有访问权限!");
      this.router.navigate(['/sign'], { queryParams: { from: state.url } });
      return false;
    }
  }

代码中初始的 let data: any = { acl: "anonymous" } 是将路由配置中未设置data参数的路由地址标记为允许匿名访问,this.acl.isAclAuthorized(data.acl) 是调用权限控制服务类(AclService)对权限码进行检查。

3.4、指定控制元素展示

权限控制指令 AclDirective 通过读取传入参数获取元素标记的权限码:

  /**
   * 传入的权限码
   */
  @Input('acl')
  set acl(value: string) {
    this.value = value;
    this.set(value);
  }

set方法通过权限码设置元素的显示状态:

  private set(val: string): void {
    const el = this.el.nativeElement;
    if (this.aclService.isAclAuthorized(val)) {
      //有权访问不做处理
    } else {
      //无权访问移除元素
      el.style = "display:none!important;"
      setTimeout(() => {
        el.remove();
      }, 100);
    }
  }

set方法中也是通过调用权限控制服务类(AclService)对权限码进行检查(this.acl.isAclAuthorized(data.acl))。当用户没有访问权限时先将元素隐藏(el.style = "display:none!important;"),再延时100ms将元素移出,添加延时是为了等待元素的渲染完成,渲染未完成时移除会引发异常。

3.5、权限控制服务类

通过权限服务类统一对用户权限进行管理,保存用户具有访问权限的全部权限码集合:

  /**
   * 设置用户权限码
   * @param acl api返回的用户权限码
   */
  setAcl(acl: Array<any>) {
    this.acl = [...acl];
    this.aclChange.next([...acl]);
  }

判断目标权限码是否在用户权限码集合中:

  /**
   * 判断用户是否具有权限码对应权限
   * @param aclCode 权限码
   */
  isAclAuthorized(aclCode: string) {
    return aclCode == "anonymous" || this.acl.findIndex(code => code == aclCode) >= 0;
  }

3.6、调用后台接口获取权限

在登录页面,调用后台登录接口,后台返回登录结果及用户对应的有权限的权限码集合。页面获取返回结果后调用权限服务控制类保存权限码集合:

  /**
   * 用户登录
   */
  signIn() {
    this.api.signIn(this.userName, this.password).subscribe(data => {
      this.acl.setAcl(data.acl);
      this.router.navigate(["a/a1"]);
    });
  }

至此,前端页面整套的权限控制机制就完全实现了。

完整项目代码:https://download.csdn.net/download/evanyanglibo/87364092

Guess you like

Origin blog.csdn.net/evanyanglibo/article/details/128549843