使用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 相关文章推荐
Ext grid 添加右击菜单
Nov 26 Javascript
Jquery 滑入滑出效果实现代码
Mar 27 Javascript
Javascript 自适应高度的Tab选项卡
Apr 05 Javascript
js实现类似jquery里animate动画效果的方法
Apr 10 Javascript
jquery二级目录选中当前页的css样式
Dec 08 Javascript
javascript 秒表计时器实现代码
Mar 09 Javascript
微信小程序中显示html格式内容的方法
Apr 25 Javascript
react native带索引的城市列表组件的实例代码
Aug 08 Javascript
浅谈Vue SPA 首屏加载优化实践
Dec 15 Javascript
详解Javascript 中的 class、构造函数、工厂函数
Dec 20 Javascript
微信小程序通过js实现瀑布流布局详解
Aug 28 Javascript
JavaScript ES6 Class类实现原理详解
May 08 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
WINXP下apache+php4+mysql
2006/11/25 PHP
php删除与复制文件夹及其文件夹下所有文件的实现代码
2013/01/23 PHP
在Mac OS的PHP环境下安装配置MemCache的全过程解析
2016/02/15 PHP
PHP将MySQL的查询结果转换为数组并用where拼接的示例
2016/05/13 PHP
PHP实现动态删除XML数据的方法示例
2018/03/30 PHP
php微信扫码支付 php公众号支付
2019/03/24 PHP
laravel-admin select框默认选中的方法
2019/10/03 PHP
javascript 复杂的嵌套环境中输出单引号和双引号
2009/05/26 Javascript
基于Jquery的仿Windows Aero弹出窗(漂亮的关闭按钮)
2010/09/28 Javascript
jquery创建并行对象或者合并对象的实现代码
2012/10/10 Javascript
IE浏览器中图片onload事件无效的解决方法
2014/04/29 Javascript
jQuery实现时尚漂亮的弹出式对话框实例
2015/08/07 Javascript
jquery实现下拉框功能效果【实例代码】
2016/05/06 Javascript
使用jsonp实现跨域获取数据实例讲解
2016/12/25 Javascript
javascript添加前置0(补零)的几种方法
2017/01/05 Javascript
BootStrap fileinput.js文件上传组件实例代码
2017/02/20 Javascript
AugularJS从入门到实践(必看篇)
2017/07/10 Javascript
JS实现DOM删除节点操作示例
2018/04/04 Javascript
JS实现的缓冲运动效果示例
2018/04/30 Javascript
JavaScript基于对象方法实现数组去重及排序操作示例
2018/07/10 Javascript
vue.js单文件组件中非父子组件的传值实例
2018/09/13 Javascript
[03:32]2014DOTA2西雅图邀请赛 CIS外卡赛赛前black专访
2014/07/09 DOTA
Python编程实现双击更新所有已安装python模块的方法
2017/06/05 Python
Python列表推导式与生成器表达式用法示例
2018/02/08 Python
Python使用Pickle库实现读写序列操作示例
2018/06/15 Python
python钉钉机器人运维脚本监控实例
2019/02/20 Python
django的autoreload机制实现
2020/06/03 Python
英国著名的小众美容品牌网站:Alyaka
2017/08/08 全球购物
北京捷通华声语音技术有限公司Java软件工程师笔试题
2012/04/10 面试题
高考自主招生自荐信
2013/10/20 职场文书
爷爷追悼会答谢词
2014/01/24 职场文书
我与祖国共奋进演讲稿
2014/09/13 职场文书
2015年教师新年寄语
2014/12/08 职场文书
小学五一劳动节活动总结
2015/02/09 职场文书
工程竣工验收申请报告
2015/05/15 职场文书
网络妈妈观后感
2015/06/08 职场文书