浅谈Angular路由守卫


Posted in Javascript onAugust 26, 2017

引言

在企业应用中权限、复杂页多路由数据处理、进入与离开路由数据处理这些是非常常见的需求。

当希望用户离开一个正常编辑页时,要中断并提醒用户是否真的要离开时,如果在Angular中应该怎么做呢?

其实Angular路由守卫属性可以帮我们做更多有意义的事,而且非常简单。

什么是路由守卫?

Angular 的 Route 路由参数中除了熟悉的 pathcomponent 外,还包括四种是否允许路由激活与离开的属性。

canActivate

控制是否允许进入路由。

canActivateChild

等同 canActivate,只不过针对是所有子路由。

canDeactivate

控制是否允许离开路由。

canLoad

控制是否允许延迟加载整个模块。

例如:

{ path: 'logics', loadChildren: './logics/logics.module#LogicsModule', canLoad: [ AuthGuard ] }

这四个属性非常好理解,而且作用各自不同。然后当进入与离开能够有效控制权时,对于前面我提到的若干问题,就可以非常好的处理。

如何创建?

四个属性虽然名称不同,但其基本的使用方式非常相近。四种不同守卫方式有者四个不同的接口与之相对应。

属性名 接口名
canActivate CanActivate
canActivateChild CanActivateChild
canDeactivate CanDeactivate
canLoad CanLoad

canDeactivate 需要指明具体的组件类名以外,其他接口只是将首字母大写而已。假定需要一个某个角色才能访问某些路由,就需要一个 CanActivate 守卫类。

@Injectable()
export class CanAdminProvide implements CanActivate {

  constructor(private userSrv: UserService, private msg: NzMessageService) {}

  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): boolean | Observable<boolean> | Promise<boolean> {
    return new Observable((observer) => {
      // 拥有 `admin` 角色
      if (this.userSrv.hasRole('admin')) {
        observer.next(true);
        observer.complete();
        return;
      }

      this.msg.error('授权不足');
      observer.next(false);
      observer.complete();
    });
  }

}

每种接口要都需要相应的实现某个方法,就上而论,继承 CanActivate 并实现一个叫 canActivate 的方法;且返回一个布尔类型的值。

四种类型守卫接口都返回一个布尔类型值,其实从这四种参数的名称 can 开头就不然理解。

最后,把它运用到相应的路由上即可,例如:

{ path: 'admin', component: GuardAdminComponent, canActivate: [ CanAdminProvide ] }

当然,别忘记注册 CanAdminProvide 类。

一些实践

离开时提醒

四种守卫只有一种离开类型 canDeactivate,因此:

@Injectable()
export class CanLeaveProvide implements CanDeactivate<GuardComponent> {
  constructor (private confirmSrv: NzModalService) {}

  canDeactivate(
    component: GuardComponent,
    currentRoute: ActivatedRouteSnapshot,
    currentState: RouterStateSnapshot,
    nextState?: RouterStateSnapshot): boolean | Observable<boolean> | Promise<boolean> {
    return new Observable((observer) => {
      this.confirmSrv.confirm({
        title: '确认要离开吗?',
        content: '你已经填写了部分表单离开会放弃已经填写的内容。',
        okText: '离开',
        cancelText: '取消',
        onOk: () => {
          observer.next(true);
          observer.complete();
        },
        onCancel: () => {
          observer.next(false);
          observer.complete();
        }
      });
    });
  }
}

这里返回的是一个 Observable 类型,意味者,在方法体内可以做任何事,只需要在结果中使用:

// 允许
observer.next(true); 
// 或拒绝
// observer.next(false);

observer.complete();

来处理 Observable 的结果,就完成了整个流程。倘若,用户按浏览器后退或路由至其他页面时,会先收到一个提醒。

上面使用的 ng-zorro-antd 的确认对话框来提醒用户是否需要离开,若选择【离开】则跳转至目标路由,反之保留当前路由状态。

浅谈Angular路由守卫

角色受限

这是再正常不过的功能,若用户进入一个未授权的路由时,甚至是某个迟延加载模块下所有路由;若用户无权限时,如何提醒用户。

此时 canActivate、canLoad 就有用了。假定管理员角色才能加载管理模块下所有管理功能以及某个管理页面,基于接口多继承的特性,可以同时继承这两个接口。

@Injectable()
export class CanAuthProvide implements CanActivate, CanLoad {

  constructor(private userSrv: UserService, private msg: NzMessageService) {}

  check(): Observable<boolean> {
    return new Observable((observer) => {
      if (this.userSrv.isLogin) {
        observer.next(true);
        observer.complete();
        return;
      }

      this.msg.error('权限不足');
      observer.next(false);
      observer.complete();
    });
  }

  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): boolean | Observable<boolean> | Promise<boolean> {
    return this.check();
  }

  canLoad(route: Route): boolean | Observable<boolean> | Promise<boolean> {
    return this.check();
  }

}

因此,一个类中具有两种不同守卫的能力,更对于代码组织也更优雅。同样,需要运用到相应的路由当中。

{ path: 'auth', component: GuardAuthComponent, canActivate: [ CanAuthProvide ] },
{ path: 'admin', loadChildren: './admin/admin.module#AdminModule', canLoad: [ CanAuthProvide ] }

此后,若一个普通员工账号要想进入(哪怕浏览器地址栏录入)未授权的路由 /auth 会提示 权限不足 的字样。

浅谈Angular路由守卫

总结

路由守卫对于权限控制非常便利,当然其粒度当然只能在页面层级。倘若需要对按钮粒度也只能利用指令的方式,而二者的结合可以极大的改善权限控制埋点的代码量。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
关于js中window.location.href,location.href,parent.location.href,top.location.href的用法与区别
Oct 18 Javascript
javascript动态加载二
Aug 22 Javascript
讨论html与javascript在浏览器中的加载顺序问题
Nov 27 Javascript
javascript动态修改Li节点值的方法
Jan 20 Javascript
微信小程序--组件(swiper)详细介绍
Jun 13 Javascript
JavaScript的六种继承方式(推荐)
Jun 26 Javascript
Vue axios 中提交表单数据(含上传文件)
Jul 06 Javascript
Vue组件开发技巧总结
Mar 04 Javascript
微信小程序wx.uploadfile 本地文件转base64的实现代码
Jun 28 Javascript
vue history 模式打包部署在域名的二级目录的配置指南
Jul 02 Javascript
小程序按钮避免多次调用接口和点击方案实现(不用showLoading)
Apr 15 Javascript
原生js实现拖拽移动与缩放效果
Aug 24 Javascript
javascript实现文字无缝滚动效果
Aug 26 #Javascript
node实现定时发送邮件的示例代码
Aug 26 #Javascript
详解webpack3如何正确引用并使用jQuery库
Aug 26 #jQuery
get  post jsonp三种数据交互形式实例详解
Aug 25 #Javascript
详解vue 模拟后台数据(加载本地json文件)调试
Aug 25 #Javascript
浅谈JS获取元素的N种方法及其动静态讨论
Aug 25 #Javascript
AngularJS select设置默认值的实现方法
Aug 25 #Javascript
You might like
关于在php.ini中添加extension=php_mysqli.dll指令的说明
2007/06/14 PHP
PHP数组传递是值传递而非引用传递概念纠正
2013/01/31 PHP
Codeigniter发送邮件的方法
2015/03/19 PHP
[原创]php实现 data url的图片生成与保存
2016/12/04 PHP
php获取给定日期相差天数的方法分析
2017/02/20 PHP
php7下的filesize函数
2019/09/30 PHP
JQUERY的属性选择符和自定义选择符使用方法(二)
2011/04/07 Javascript
Bootstrap每天必学之导航条(二)
2016/03/01 Javascript
原生js实现可爱糖果数字时间特效
2016/12/30 Javascript
JavaScript实现弹出广告功能
2017/03/30 Javascript
Vuejs仿网易云音乐实现听歌及搜索功能
2017/03/30 Javascript
IScroll那些事_当内容不足时下拉刷新的解决方法
2017/07/18 Javascript
纯js实现的积木(div层)拖动功能示例
2017/07/19 Javascript
JS实现前端缓存的方法
2017/09/21 Javascript
微信小程序实现商城倒计时
2020/11/01 Javascript
vue中如何实现后台管理系统的权限控制的方法步骤
2019/09/05 Javascript
JS数据类型(基本数据类型、引用数据类型)及堆和栈的区别分析
2020/03/04 Javascript
[01:54]TI珍贵瞬间系列(五):压力
2020/08/29 DOTA
python抓取网页图片并放到指定文件夹
2014/04/24 Python
django开发教程之利用缓存文件进行页面缓存的方法
2017/11/10 Python
python 获取字符串MD5值方法
2018/05/29 Python
python批量复制图片到另一个文件夹
2018/09/17 Python
Python3安装pip工具的详细步骤
2019/10/14 Python
解决pycharm 安装numpy失败的问题
2019/12/05 Python
香蕉共和国Banana Republic官网:美国GAP旗下偏贵族风格服饰品牌
2016/11/21 全球购物
Joules官网:女士、男士和儿童服装和鞋类
2018/10/23 全球购物
Myprotein比利时官方网站:欧洲第一运动营养品牌
2020/10/04 全球购物
描述Cookie和Session的作用,区别和各自的应用范围,Session工作原理
2015/03/25 面试题
家长会邀请书
2014/01/25 职场文书
运动会广播稿500字
2014/01/28 职场文书
工伤死亡理赔协议书
2014/10/20 职场文书
小学五年级语文上册教学计划
2015/01/22 职场文书
幼儿园亲子活动通知
2015/04/24 职场文书
六一儿童节新闻稿
2015/07/17 职场文书
感谢信的技巧及范例
2019/05/15 职场文书
MySQL数据库索引的最左匹配原则
2021/11/20 MySQL