使用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 相关文章推荐
仿校内登陆框,精美,给那些很厉害但是没有设计天才的程序员
Nov 24 Javascript
JS+CSS实现鼠标经过弹出一个DIV框完整实例(带缓冲动画渐变效果)
Mar 25 Javascript
angularjs利用directive实现移动端自定义软键盘的示例
Sep 20 Javascript
Angular2.0/4.0 使用Echarts图表的示例代码
Dec 07 Javascript
如何获取TypeScript的声明文件.d.ts
May 01 Javascript
webpack分离css单独打包的方法
Jun 12 Javascript
如何在项目中使用log4.js的方法步骤
Jul 16 Javascript
ES6基础之数组和对象的拓展实例详解
Aug 22 Javascript
layui use 定义js外部引用函数的方法
Sep 26 Javascript
leaflet加载geojson叠加显示功能代码
Feb 21 Javascript
vue实现移动端触屏拖拽功能
Aug 21 Javascript
js实现简单的点名器随机色实例代码
Sep 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
一个简单的域名注册情况查询程序
2006/10/09 PHP
探讨方法的重写(覆载)详解
2013/06/08 PHP
php使用ZipArchive提示Fatal error: Class ZipArchive not found in的解决方法
2014/11/04 PHP
ie 处理 gif动画 的onload 事件的一个 bug
2007/04/12 Javascript
ExtJS Grid使用SimpleStore、多选框的方法
2009/11/20 Javascript
关于文本框的一些限制控制总结~~
2010/04/15 Javascript
为JavaScript添加重载函数的辅助方法
2010/07/04 Javascript
JS的Document属性和方法小结
2013/09/17 Javascript
移动节点的jquery代码
2014/01/13 Javascript
Jquery中ajax方法data参数的用法小结
2014/02/12 Javascript
jquery ajaxSubmit 异步提交的简单实现
2014/02/28 Javascript
javascript实现状态栏中文字动态显示的方法
2015/10/20 Javascript
JavaScript中获取Radio被选中的值
2015/11/11 Javascript
正则验证小数点后面只能有两位数的方法
2017/02/28 Javascript
bootstrap+jQuery 实现下拉菜单中复选框全选和全不选效果
2017/06/12 jQuery
实例详解JavaScript中setTimeout函数的执行顺序
2017/07/12 Javascript
jQuery简单实现对数组去重及排序操作实例
2017/10/31 jQuery
Vuex 快速入门(简单易懂)
2018/09/20 Javascript
Node.js中Koa2在控制台输出请求日志的方法示例
2019/05/02 Javascript
Vue动态创建注册component的实例代码
2019/06/14 Javascript
详解Vue 换肤方案验证
2019/08/28 Javascript
微信小程序HTTP接口请求封装代码实例
2019/09/05 Javascript
jQuery高级编程之js对象、json与ajax用法实例分析
2019/11/01 jQuery
[36:02]DOTA2上海特级锦标赛D组小组赛#2 Liquid VS VP第一局
2016/02/28 DOTA
[02:21]2018完美盛典章节片——初心
2018/12/17 DOTA
python基础教程之元组操作使用详解
2014/03/25 Python
Python序列类型的打包和解包实例
2019/12/21 Python
解决import tensorflow as tf 出错的原因
2020/04/16 Python
在HTML5中使用MathML数学公式的简单讲解
2016/02/19 HTML / CSS
写好求职应聘自荐信的三部曲
2013/09/21 职场文书
大学生活学习的自我评价
2013/12/03 职场文书
数学教研活动总结
2014/07/02 职场文书
晚会闭幕词
2015/01/28 职场文书
2016高考寄语集锦
2015/12/04 职场文书
创业计划书之小型广告公司
2019/10/22 职场文书
整理Python中常用的conda命令操作
2021/06/15 Python