使用AngularJS对路由进行安全性处理的方法


Posted in Javascript onJune 18, 2015

 简介

自从出现以后,AngularJS已经被使用很长时间了。 它是一个用于开发单页应用(SPA)的javascript框架。 它有一些很好的特性,如双向绑定、指令等。 这篇文章主要介绍Angular路由安全性策略。 它是一个可用Angular开发实现的客户端安全性框架。 我已经对它进行了测试。 除了保证客户端路由安全性外,你也需要保证服务器端访问的安全性。 客户端安全性策略有助于减少对服务器进行额外的访问。 然而,如果一些人采用欺骗浏览器的手段访问服务器,那么服务器端安全性策略应当能够拒绝未授权的访问。 在这篇文章中,我仅对客户端安全性策略进行讨论。

1  在应用模块层面定义全局变量

为应用定义角色:
 

var roles = {
  superUser: 0,
  admin: 1,
  user: 2
};

为应用定义未授权访问的路由:

var routeForUnauthorizedAccess = '/SomeAngularRouteForUnauthorizedAccess';

2 定义授权服务
 

appModule.factory('authorizationService', function ($resource, $q, $rootScope, $location) {
  return {
    // 将权限缓存到 Session,以避免后续请求不停的访问服务器
    permissionModel: { permission: {}, isPermissionLoaded: false },
 
    permissionCheck: function (roleCollection) {
      // 返回一个承诺(promise).
      var deferred = $q.defer();
 
      // 这里只是在承诺的作用域中保存一个指向上层作用域的指针。
      var parentPointer = this;
 
      // 检查是否已从服务获取到权限对象(已登录用户的角色列表)
      if (this.permissionModel.isPermissionLoaded) {
 
        // 检查当前用户是否有权限访问当前路由
        this.getPermission(this.permissionModel, roleCollection, deferred);
      } else {
        // 如果还没权限对象,我们会去服务端获取。
        // 'api/permissionService' 是本例子中的 web 服务地址。
 
        $resource('/api/permissionService').get().$promise.then(function (response) {
          // 当服务器返回之后,我们开始填充权限对象
          parentPointer.permissionModel.permission = response;
 
          // 将权限对象处理完成的标记设为 true 并保存在 Session,
          // Session 中的用户,在后续的路由请求中可以重用该权限对象
          parentPointer.permissionModel.isPermissionLoaded = true;
 
          // 检查当前用户是否有必须角色访问该路由
          parentPointer.getPermission(parentPointer.permissionModel, roleCollection, deferred);
        }
        );
      }
      return deferred.promise;
    },
 
    //方法:检查当前用户是否有必须角色访问该路由
    //'permissionModel' 保存了从服务端返回的当前用户的角色信息
    //'roleCollection' 保存了可访问当前路由的角色列表
    //'deferred' 是用来处理承诺的对象
    getPermission: function (permissionModel, roleCollection, deferred) {
      var ifPermissionPassed = false;
 
      angular.forEach(roleCollection, function (role) {
        switch (role) {
          case roles.superUser:
            if (permissionModel.permission.isSuperUser) {
              ifPermissionPassed = true;
            }
            break;
          case roles.admin:
            if (permissionModel.permission.isAdministrator) {
              ifPermissionPassed = true;
            }
            break;
          case roles.user:
            if (permissionModel.permission.isUser) {
              ifPermissionPassed = true;
            }
            break;
          default:
            ifPermissionPassed = false;
        }
      });
      if (!ifPermissionPassed) {
        // 如果用户没有必须的权限,我们把用户引导到无权访问页面
        $location.path(routeForUnauthorizedAccess);
        // 由于这个处理会有延时,而这期间页面位置可能发生改变, 
        // 我们会一直监视 $locationChangeSuccess 事件
        // 并且当该事件发生的时,就把掉承诺解决掉。
        $rootScope.$on('$locationChangeSuccess', function (next, current) {
          deferred.resolve();
        });
      } else {
        deferred.resolve();
      }
    }
  };
});

3 加密路由

然后让我们用我们的努力成果来加密路由:
 

var appModule = angular.module("appModule", ['ngRoute', 'ngResource'])
  .config(function ($routeProvider, $locationProvider) {
    $routeProvider
      .when('/superUserSpecificRoute', {
        templateUrl: '/templates/superUser.html', // 路由的 view/template 路径
        caseInsensitiveMatch: true,
        controller: 'superUserController', // 路由的 angular 控制器
        resolve: {
          // 在这我们将使用我们上面的努力成果,调用授权服务
          // resolve 是 angular 中一个非常赞的特性,可以确保
          // 只有当它下面提到的承诺被处理之后
          // 才将控制器(在本例中是 superUserController)应用到路由。
          permission: function (authorizationService, $route) {
            return authorizationService.permissionCheck([roles.superUser]);
          },
        }
      })
      .when('/userSpecificRoute', {
        templateUrl: '/templates/user.html',
        caseInsensitiveMatch: true,
        controller: 'userController',
        resolve: {
          permission: function (authorizationService, $route) {
            return authorizationService.permissionCheck([roles.user]);
          },
        }
      })
      .when('/adminSpecificRoute', {
        templateUrl: '/templates/admin.html',
        caseInsensitiveMatch: true,
        controller: 'adminController',
        resolve: {
          permission: function (authorizationService, $route) {
            return authorizationService.permissionCheck([roles.admin]);
          },
        }
      })
      .when('/adminSuperUserSpecificRoute', {
        templateUrl: '/templates/adminSuperUser.html',
        caseInsensitiveMatch: true,
        controller: 'adminSuperUserController',
        resolve: {
          permission: function (authorizationService, $route) {
            return authorizationService.permissionCheck([roles.admin, roles.superUser]);
          },
        }
      });
  });
Javascript 相关文章推荐
Web版彷 Visual Studio 2003 颜色选择器
Jan 09 Javascript
永不消失的title提示代码
Feb 15 Javascript
扩展jQuery 键盘事件的几个基本方法
Oct 30 Javascript
容易被忽略的JS脚本特性
Sep 13 Javascript
jquery和css3实现的炫酷时尚的菜单导航
Sep 01 Javascript
JS实现从表格中动态删除指定行的方法
Mar 31 Javascript
JQuery创建DOM节点的方法
Jun 11 Javascript
使用Raygun对Node.js应用进行错误处理的方法
Jun 23 Javascript
Angularjs实现多个页面共享数据的方式
Mar 29 Javascript
vue中子组件调用兄弟组件方法
Jul 06 Javascript
javascript实现画板功能
Apr 12 Javascript
VUE+elementui组件在table-cell单元格中绘制微型echarts图
Apr 20 Javascript
浅谈Node.js中的定时器
Jun 18 #Javascript
浅析AngularJS中的生命周期和延迟处理
Jun 18 #Javascript
Node.js事件驱动
Jun 18 #Javascript
详解AngularJS的通信机制
Jun 18 #Javascript
javascript背景时钟实现方法
Jun 18 #Javascript
移动Web中图片自适应的两种JavaScript解决方法
Jun 18 #Javascript
javascript随机显示背景图片的方法
Jun 18 #Javascript
You might like
PHP中利用substr_replace将指定两位置之间的字符替换为*号
2011/01/27 PHP
PHP __autoload函数(自动载入类文件)的使用方法
2012/02/04 PHP
PHP模板引擎Smarty内建函数foreach,foreachelse用法分析
2016/04/11 PHP
PHP+Ajax验证码验证用户登录
2016/07/20 PHP
PHP中如何判断exec函数执行成功?
2016/08/04 PHP
PHP入门教程之数组用法汇总(创建,删除,遍历,排序等)
2016/09/11 PHP
Thinkphp5.0框架的Db操作实例分析【连接、增删改查、链式操作等】
2019/10/11 PHP
js日期对象兼容性的处理方法
2014/01/28 Javascript
js读取配置文件自写
2014/02/11 Javascript
用JavaScript实现用一个DIV来包装文本元素节点
2014/09/09 Javascript
javascript制作坦克大战全纪录(2)
2014/11/27 Javascript
基于Bootstrap+jQuery.validate实现表单验证
2016/05/30 Javascript
connection reset by peer问题总结及解决方案
2016/10/21 Javascript
基于vuejs+webpack的日期选择插件
2020/05/21 Javascript
使用纯JS代码判断字符串中有多少汉字的实现方法(超简单实用)
2016/11/12 Javascript
jQuery实现加入收藏夹功能(主流浏览器兼职)
2016/12/24 Javascript
JavaScript中的call和apply的用途以及区别
2017/01/11 Javascript
史上最全JavaScript常用的简写技巧(推荐)
2017/08/17 Javascript
vue.js整合mint-ui里的轮播图实例代码
2017/12/27 Javascript
详解解决使用axios发送json后台接收不到的问题
2018/06/27 Javascript
vue+axios+promise实际开发用法详解
2018/10/15 Javascript
react quill中图片上传由默认转成base64改成上传到服务器的方法
2019/10/30 Javascript
利用Python中的输入和输出功能进行读取和写入的教程
2015/04/14 Python
基于Python和Scikit-Learn的机器学习探索
2017/10/16 Python
使用python编写监听端
2018/04/12 Python
python excel使用xlutils类库实现追加写功能的方法
2018/05/02 Python
python SVD压缩图像的实现代码
2019/11/05 Python
Python利用全连接神经网络求解MNIST问题详解
2020/01/14 Python
为什么黑客都用python(123个黑客必备的Python工具)
2020/01/31 Python
python实现KNN近邻算法
2020/12/30 Python
MYSQL支持事务吗
2013/08/09 面试题
自动化工程专业个人应聘自荐信
2013/09/26 职场文书
公司综合部的成员自我评价分享
2013/11/05 职场文书
师范院校学生自荐信范文
2013/12/27 职场文书
毕业大学生自荐信
2014/06/17 职场文书
初中班长竞选稿
2015/11/20 职场文书