7

我正在创建一个 Web 应用程序,它将满足用户的两个要求。注意:我是 AngularJS 作为 Web 开发平台的新手。

前端 - 1:它是一种搜索功能,用户可以根据关键字搜索和过滤器搜索特定文档和研究。这是使用 MySQL 实现的,用于使用 AngularJS 获取数据和显示。

前端 - 2:用户可以选择在 Web 应用程序上创建帐户。该帐户的目的是:

  1. 保存他们的搜索查询。
  2. 如果管理员将每个用户与特定角色相关联,那么这些用户将可以访问额外的选项,例如修改数据库中的文档以及上传新文档和其他页面的主机。

我的问题:

如何在 AngularJS 中处理基于角色的授权?我无法弄清楚如何创建一个涉及以下功能的框架: - 用户获得与他们关联的角色 - 阻止用户访问与这些角色无关的页面或功能

我已经阅读了几篇 SO 文章和教程,但每个教程都以作者说基于角色的授权应该在服务器端处理,我理解为什么这是真的。

如果有人可以向我指出在 AngularJS 的服务器端实现了基于角色的授权的教程或文章,那就太好了。

谢谢!

4

1 回答 1

10

我在后端和前端使用基于角色的授权。由于我使用 UI-Router 进行路由,因此我发现(并根据我的需要进行了改进)的最佳资源是这篇文章:

链接已过期

如果您使用 UI Router,请务必检查一下。基本上,您需要设置路线安全性并拦截所有路线更改。如果用户无权访问其背后的内容,该文章还包括隐藏用户界面元素的指令。


编辑:添加一些代码。

首先,您需要将用户的权限存储在某处,例如在 localStorage 中序列化的用户对象上:

{"id":1,"name":"user","created_at":"2016-04-17 18:58:19","gender":"m","roles":["admin"]}

然后,您有两个重要部分:

  • 指令 - 根据分配的权限确定元素是否应该可见
  • service - 处理授权检查

指示:

(function() {
  'use strict';

  angular
    .module('app')
    .directive('access', access);

  /** @ngInject */
  function access(authorization) {
    var directive = {
      restrict: 'A',
      link: linkFunc,
    };

    return directive;

    /** @ngInject */
    function linkFunc($scope, $element, $attrs) {
      var makeVisible = function () {
        $element.removeClass('hidden');
      };

      var makeHidden = function () {
        $element.addClass('hidden');
      };

      var determineVisibility = function (resetFirst) {
        var result;

        if (resetFirst) {
          makeVisible();
        }

        result = authorization.authorize(true, roles, $attrs.accessPermissionType);

        if (result === authorization.constants.authorised) {
          makeVisible();
        } else {
          makeHidden();
        }
      };

      var roles = $attrs.access.split(',');

      if (roles.length > 0) {
          determineVisibility(true);
      }
    }
  }

})();

您需要设置您的 CSS 以使具有类的元素hidden不可见。

服务:

(function() {
  'use strict';

  angular
    .module('app')
    .factory('authorization', authorization);

  /** @ngInject */
  function authorization($rootScope) {
    var service = {
      authorize: authorize,
      constants: {
        authorised: 0,
        loginRequired: 1,
        notAuthorised: 2
      }
    };

    return service;

    function authorize(loginRequired, requiredPermissions, permissionCheckType) {
      var result = service.constants.authorised,
          user = $rootScope.currentUser,
          loweredPermissions = [],
          hasPermission = true,
          permission;

      permissionCheckType = permissionCheckType || 'atLeastOne';

      if (loginRequired === true && user === undefined) {
          result = service.constants.loginRequired;

      } else if ((loginRequired === true && user !== undefined) &&
                  (requiredPermissions === undefined || requiredPermissions.length === 0)) {
          result = service.constants.authorised;

      } else if (requiredPermissions) {

          loweredPermissions = [];

          angular.forEach(user.roles, function (permission) {
              loweredPermissions.push(permission.toLowerCase());
          });

          for (var i = 0; i < requiredPermissions.length; i += 1) {
              permission = requiredPermissions[i].toLowerCase();

              if (permissionCheckType === 'combinationRequired') {
                  hasPermission = hasPermission && loweredPermissions.indexOf(permission) > -1;
                  // if all the permissions are required and hasPermission is false there is no point carrying on
                  if (hasPermission === false) {
                      break;
                  }
              } else if (permissionCheckType === 'atLeastOne') {
                  hasPermission = loweredPermissions.indexOf(permission) > -1;
                  // if we only need one of the permissions and we have it there is no point carrying on
                  if (hasPermission) {
                      break;
                  }
              }
          }

          result = hasPermission ?
                   service.constants.authorised :
                   service.constants.notAuthorised;
      }

      return result;
    }
  }
})();

现在,您可以使用该指令来显示/隐藏元素:

<a ui-sref="app.administration" class="btn btn-primary pull-right" access="admin">Administration</a>

当然这只会隐藏DOM中的元素,所以你也必须在服务器上进行授权检查。

第一部分解决了在用户界面中显示/隐藏元素,但您也可以保护应用程序路由。

路线定义:

(function() {
  'use strict';

  angular
    .module('app')
    .config(routeConfig);

  /** @ngInject */
  function routeConfig($stateProvider) {
    $stateProvider
      .state('app.dashboard', {
        url: '/dashboard',
        data: {
          access: {
            loginRequired: true
          }
        },
        templateUrl: 'template_path',
        controller: 'DashboardController as vm'
      }
  }
})();

现在只需检查$stateChangeStart事件的许可

(function() {
  'use strict';

  angular
    .module('app')
    .run(runBlock);

  /** @ngInject */
  function runBlock($rootScope, $state, authorization) {
    $rootScope.$on('$stateChangeStart', function(event, toState) {
      // route authorization check
      if (toState.data !== undefined && toState.data.access !== undefined) {
        authorised = authorization.authorize(toState.data.access.loginRequired,
                                             toState.data.access.requiredPermissions,
                                             toState.data.access.permissionCheckType);

        if (authorised === authorization.constants.loginRequired) {
          event.preventDefault();
          $state.go('app.login');
        } else if (authorised === authorization.constants.notAuthorised) {
          event.preventDefault();
          $state.go('app.dashboard');
        }
      }
    });
  }

})();
于 2015-10-27T18:09:23.830 回答