为了账号安全,请及时绑定邮箱和手机立即绑定

AngularJS用户界面-路由器登录认证

AngularJS用户界面-路由器登录认证

Helenr 2019-07-04 18:18:48
AngularJS用户界面-路由器登录认证我是AngularJS的新手,我对如何在以下场景中使用角-“UI-路由器”感到有点困惑:我正在构建一个由两个部分组成的Web应用程序。第一部分是主页及其登录和注册视图,第二部分是仪表板(成功登录后)。我创造了一个index.html对于家庭部分,它的角度应用程序和ui-router要处理的配置/login和/signup视图,还有另一个文件dashboard.html用于仪表板部分及其应用程序和ui-router配置来处理许多子视图。现在我完成了仪表板部分,不知道如何将这两个部分与它们不同的角度应用程序结合起来。我如何告诉家庭应用程序重定向到仪表板应用程序?
查看完整描述

3 回答

?
达令说

TA贡献1821条经验 获得超6个赞

我正在制作一个更好的演示,并将其中的一些服务清理成一个可用的模块,但下面是我想出的。这是一个复杂的过程,以解决一些注意事项,所以坚持住。你需要把它分解成几块。

看看这个.

首先,您需要一个服务来存储用户的身份。我称之为principal..它可以被检查以查看用户是否登录,并且根据请求,它可以解析一个表示有关用户身份的基本信息的对象。这可以是您需要的任何东西,但是基本要素是显示名称、用户名、可能是电子邮件,以及用户所属的角色(如果这适用于您的应用程序)。主体还具有执行角色检查的方法。

.factory('principal', ['$q', '$http', '$timeout',
  function($q, $http, $timeout) {
    var _identity = undefined,
      _authenticated = false;

    return {
      isIdentityResolved: function() {
        return angular.isDefined(_identity);
      },
      isAuthenticated: function() {
        return _authenticated;
      },
      isInRole: function(role) {
        if (!_authenticated || !_identity.roles) return false;

        return _identity.roles.indexOf(role) != -1;
      },
      isInAnyRole: function(roles) {
        if (!_authenticated || !_identity.roles) return false;

        for (var i = 0; i < roles.length; i++) {
          if (this.isInRole(roles[i])) return true;
        }

        return false;
      },
      authenticate: function(identity) {
        _identity = identity;
        _authenticated = identity != null;
      },
      identity: function(force) {
        var deferred = $q.defer();

        if (force === true) _identity = undefined;

        // check and see if we have retrieved the 
        // identity data from the server. if we have, 
        // reuse it by immediately resolving
        if (angular.isDefined(_identity)) {
          deferred.resolve(_identity);

          return deferred.promise;
        }

        // otherwise, retrieve the identity data from the
        // server, update the identity object, and then 
        // resolve.
        //           $http.get('/svc/account/identity', 
        //                     { ignoreErrors: true })
        //                .success(function(data) {
        //                    _identity = data;
        //                    _authenticated = true;
        //                    deferred.resolve(_identity);
        //                })
        //                .error(function () {
        //                    _identity = null;
        //                    _authenticated = false;
        //                    deferred.resolve(_identity);
        //                });

        // for the sake of the demo, fake the lookup
        // by using a timeout to create a valid
        // fake identity. in reality,  you'll want 
        // something more like the $http request
        // commented out above. in this example, we fake 
        // looking up to find the user is
        // not logged in
        var self = this;
        $timeout(function() {
          self.authenticate(null);
          deferred.resolve(_identity);
        }, 1000);

        return deferred.promise;
      }
    };
  }])

其次,您需要一个服务来检查用户想要进入的状态,确保他们已经登录(如果必要的话;对于签名、密码重置等等来说不需要),然后进行角色检查(如果您的应用程序需要这样的话)。如果未对其进行身份验证,请将其发送到登录页。如果它们经过身份验证,但未通过角色检查,则将它们发送到拒绝访问的页面。我叫这个服务authorization.

.factory('authorization', ['$rootScope', '$state', 'principal',
  function($rootScope, $state, principal) {
    return {
      authorize: function() {
        return principal.identity()
          .then(function() {
            var isAuthenticated = principal.isAuthenticated();

            if ($rootScope.toState.data.roles                && $rootScope.toState                             
            .data.roles.length > 0 
                && !principal.isInAnyRole(
                   $rootScope.toState.data.roles))
            {
              if (isAuthenticated) {
                  // user is signed in but not
                  // authorized for desired state
                  $state.go('accessdenied');
              } else {
                // user is not authenticated. Stow
                // the state they wanted before you
                // send them to the sign-in state, so
                // you can return them when you're done
                $rootScope.returnToState                    = $rootScope.toState;
                $rootScope.returnToStateParams                    = $rootScope.toStateParams;

                // now, send them to the signin state
                // so they can log in
                $state.go('signin');
              }
            }
          });
      }
    };
  }])

现在你要做的就是倾听ui-router$stateChangeStart..这使您有机会检查当前状态、他们希望进入的状态,并插入授权检查。如果失败,您可以取消路由转换,或者更改为其他路由。

.run(['$rootScope', '$state', '$stateParams', 
      'authorization', 'principal',
    function($rootScope, $state, $stateParams, 
             authorization, principal){
      $rootScope.$on('$stateChangeStart', 
          function(event, toState, toStateParams)
      {
        // track the state the user wants to go to; 
        // authorization service needs this
        $rootScope.toState = toState;
        $rootScope.toStateParams = toStateParams;
        // if the principal is resolved, do an 
        // authorization check immediately. otherwise,
        // it'll be done when the state it resolved.
        if (principal.isIdentityResolved()) 
            authorization.authorize();
      });
    }
  ]);

跟踪用户身份的棘手部分是,如果您已经通过了身份验证,就查找它(例如,您在上一次会话之后访问该页面,并在cookie中保存了一个auth令牌,或者您可能很难刷新页面,或者从链接中拖到URL上)。因为这条路ui-router有效,您需要在检查之前完成一次身份解析。您可以使用resolve选项在状态配置中。对于所有状态继承的站点,我有一个父状态,它强制在发生其他任何事情之前解析主体。

$stateProvider.state('site', {
  'abstract': true,
  resolve: {
    authorize: ['authorization',
      function(authorization) {
        return authorization.authorize();
      }
    ]
  },
  template: '<div ui-view />'})

还有另一个问题.。resolve只接到一次电话。一旦您的身份查找承诺完成,它将不再运行解决委托。因此,我们必须在两个地方进行您的检查:一是按照您的身份承诺进行检查,二是在resolve,这将涵盖您的应用程序第一次加载,并在其中一次加载。$stateChangeStart如果决议已经完成,这将涵盖您在各州之间导航的任何时间。

好吧,到目前为止我们做了什么?

  1. 我们检查应用程序何时加载,如果用户登录。
  2. 我们跟踪有关登录用户的信息。
  3. 我们将它们重定向到状态签名,以获取需要用户登录的状态。
  4. 如果它们没有访问权限,我们会将它们重定向到拒绝访问的状态。
  5. 如果需要用户登录,我们有一种机制可以将用户重定向回他们请求的原始状态。
  6. 我们可以签出一个用户(需要与管理您的auth票证的任何客户端或服务器代码进行协调)。
  7. 我们

    每次用户重新加载浏览器或删除链接时,都需要将用户送回登录页面。

我们从这里去哪儿?你可以把你的州组织成需要登录的区域。您可以通过添加data带着roles对于这些状态(如果要使用继承,则为它们的父状态)。在这里,我们将资源限制为管理员:

.state('restricted', {
    parent: 'site',
    url: '/restricted',
    data: {
      roles: ['Admin']
    },
    views: {
      'content@': {
        templateUrl: 'restricted.html'
      }
    }
  })

现在,您可以按州控制用户可以访问的路由。还有其他担心吗?可能只根据它们是否登录来更改视图的一部分?没问题。使用principal.isAuthenticated()甚至principal.isInRole()使用多种方法中的任何一种,您都可以有条件地显示模板或元素。

首先,注射principal放入控制器或任何东西中,并将其固定在作用域上,以便您可以轻松地在视图中使用它:

.scope('HomeCtrl', ['$scope', 'principal', 
    function($scope, principal){
  $scope.principal = principal;});

显示或隐藏元素:

<div ng-show="principal.isAuthenticated()">
   I'm logged in</div><div ng-hide="principal.isAuthenticated()">
  I'm not logged in</div>

等等。无论如何,在您的示例应用程序中,您将有一个主页状态,允许未经身份验证的用户来访。它们可以有登录或注册状态的链接,也可以将这些表单内置到页面中。任何适合你的。

仪表板页都可以从一个要求用户登录的状态继承,例如,它是一个User角色成员。我们讨论过的所有授权内容都是从那里流出来的。


查看完整回答
反对 回复 2019-07-04
  • 3 回答
  • 0 关注
  • 1085 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信