将自定义服务插入 UI 路由

Plugging a custom service to UI Route

我开发了一个应用程序,它成功地使用 ADAL JS 库进行 Azure 身份验证。但是我还需要实现授权,我的意思是我需要限制特定组的视图。

我已经有一个 REST API,给定用户 ID 或电子邮件可以 return 我知道他所属的组。

但是我不确定如何插入一个 angular 服务来使用 REST API 并将其插入到路由配置中。

app.js

(function () {
    angular.module('inspinia', [
        'ui.router',                    // Routing
        'oc.lazyLoad',                  // ocLazyLoad
        'ui.bootstrap',                 // Ui Bootstrap
        'pascalprecht.translate',       // Angular Translate
        'ngIdle',                       // Idle timer
        'AdalAngular',                  // ADAL JS Angular
        'ngRoute'                       // Routing
    ])
})();

config.js

function config($stateProvider, $urlRouterProvider, $ocLazyLoadProvider, IdleProvider, KeepaliveProvider,adalAuthenticationServiceProvider, $httpProvider) {

    // Configure Idle settings
    IdleProvider.idle(5); // in seconds
    IdleProvider.timeout(120); // in seconds

    $urlRouterProvider.otherwise("/dashboards/dashboard_1");

    $ocLazyLoadProvider.config({
        // Set to true if you want to see what and when is dynamically loaded
        debug: false
    });

    $stateProvider

        .state('dashboards', {
            abstract: true,
            url: "/dashboards",
            templateUrl: "views/common/content.html",
        })
        .state('dashboards.dashboard_1', {
            url: "/dashboard_1",
            templateUrl: "views/dashboard_1.html",
            requireADLogin: true,
            resolve: {
                loadPlugin: function ($ocLazyLoad) {
                    return $ocLazyLoad.load([
                        {

                            serie: true,
                            name: 'angular-flot',
                            files: [ 'js/plugins/flot/jquery.flot.js', 'js/plugins/flot/jquery.flot.time.js', 'js/plugins/flot/jquery.flot.tooltip.min.js', 'js/plugins/flot/jquery.flot.spline.js', 'js/plugins/flot/jquery.flot.resize.js', 'js/plugins/flot/jquery.flot.pie.js', 'js/plugins/flot/curvedLines.js', 'js/plugins/flot/angular-flot.js', ]
                        },
                        {
                            name: 'angles',
                            files: ['js/plugins/chartJs/angles.js', 'js/plugins/chartJs/Chart.min.js']
                        },
                        {
                            name: 'angular-peity',
                            files: ['js/plugins/peity/jquery.peity.min.js', 'js/plugins/peity/angular-peity.js']
                        }
                    ]);
                }
            }
        })

理想情况下,我可以为每个状态添加一个新的 属性,称为 Groups,其值为:

类似于:

 url: "/dashboard_1",
                templateUrl: "views/dashboard_1.html",
                requireADLogin: true,
                groups: "Admin, Accounting, Marketing"

然后后台的自定义服务将对此进行验证。

我不是特别熟悉 ADAL.js,但假设你可以在 http 请求中对服务器说 "does this user have any of these roles",那么你可以拦截 $stateChangeStart,防止通过调用 event.preventDefault() 更改状态,询问服务器当前用户是否属于 toState 中指定的任何具有访问权限的角色,然后采取任何一种方式采取行动 - 发送到拒绝访问页面,或继续到 toState.

以下是一个有缺陷的实现。工作版本被锁在工作中,我现在在家,但希望它能给你一些想法。

(function (app) {
  "use strict";

  app.run(run);

  function run($rootScope, $log, $state, $q, authService) {

    /**
     * The canceller is passed to the authService.isTokenValid()
     *
     * The canceller is a promise, that, when resolved, cancels the current
     * token validation request
     */
    let _canceller;

    /**
     * When state is changed, ensure that the current user has access
     * @param event
     * @param toState
     */
    function onStateChangeStart(event, toState, toParams) {

      // When token is valid, continue with navigation to the state
      function onValidToken() {
        if (toState.name === 'login'){
          $state.go('home');
        } else {
          $state.go(toState, toParams, {notify: false}).then((state) => {
            $rootScope.$broadcast('$stateChangeSuccess', state, null);
          });
        }
      }

      // When the token is not valid, set state to login
      function onInvalidToken() {
        if (toState.name === 'login'){
          $state.go(toState, toParams, {notify: false}).then((state) => {
            $rootScope.$broadcast('$stateChangeSuccess', state, null);
          });
        } else {
          $log.warn(`Access denied to state ${toState.name}`);
          $state.go('login');
        }
      }

      // On completion of token validation, resolve the canceller
      function onFinally() {
        if (_canceller) {
          _canceller.resolve();
        }
      }

      // If the state requiresLogin
      if (toState.requiresLogin || toState.name === 'login') {

        // stop navigation
        event.preventDefault();

        // Cancel any current requests
        if (_canceller) {
          _canceller.resolve();
        }

        // create a new promise
        _canceller = $q.defer();

        // validate
        authService.isTokenValid(_canceller)
          .then(onValidToken, onInvalidToken)
          .finally(onFinally);
      }
    }

    $rootScope.$on('$stateChangeStart', onStateChangeStart);



  }

}(angular.module('app.features')));