我是AngularJS的新手,对于如何在以下场景中使用AngularJS——"ui路由",我有点困惑:

我正在构建一个由两部分组成的web应用程序.第一部分是带有登录和注册视图的主页,第二部分是仪表板(成功登录后).

我已经用它的Angular 应用程序和ui-router配置为主页部分创建了一个index.html来处理/login/signup个视图, 并且存在用于仪表板部分的另一个文件dashboard.html及其APP和ui-router配置以处理许多子视图.

现在我完成了仪表板部分,不知道如何将这两个部分与它们不同Angular 的应用程序结合起来.我如何告诉家庭应用程序重定向到仪表板应用程序?

推荐答案

我正在制作一个更好的演示,并将其中一些服务清理成一个可用的模块,但以下是我的 idea .这是一个复杂的过程,需要解决一些警告,所以要坚持下go .你需要把它分解成几个部分.

Take a look at this plunk

首先,您需要一个服务来存储用户的身份.我称之为principal.可以判断用户是否已登录,并根据请求解析表示用户身份基本信息的对象.这可以是您需要的任何内容,但基本要素是显示名称、用户名、可能的邮箱,以及用户所属的角色(如果这适用于您的应用程序).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中,或者您可能硬刷新了页面,或者从链接拖放到URL上),则需要进行查找.由于ui-router的工作方式,您需要在身份验证判断之前进行一次身份解析.您可以使用状态配置中的resolve选项来完成此操作.我有一个站点的父状态,所有状态都继承自该父状态,它强制在发生任何其他事情之前解析主体.

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

这里还有一个问题...resolve只会被呼叫一次.一旦完成身份查找promise ,它就不会再次运行resolve委托.因此,我们必须在两个地方对你的身份进行验证:一次是根据你的身份promise 在resolve年内解析,这涵盖了你的应用程序首次加载的时间;另一次是在$stateChangeStart年内解析完成的时间,这涵盖了你在各州的任何时间.

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

  1. 如果用户已登录,我们会判断应用程序何时加载.
  2. 我们跟踪有关登录用户的信息.
  3. 我们将它们重定向到需要用户登录的状态的登录状态.
  4. 如果他们没有访问权限,我们会将他们重定向到拒绝访问状态.
  5. 如果我们需要用户登录,我们有一种机制可以将用户重定向回他们请求的原始状态.
  6. 我们可以注销用户(需要与管理您的身份验证票证的任何客户端或服务器代码连接).
  7. 每当用户重新加载浏览器或点击链接时,我们don't都需要将用户送回登录页面.

我们从这里go 哪儿?嗯,您可以将您的州组织成需要登录的区域.您可以通过将dataroles添加到这些状态(如果要使用继承,则将它们的父级)添加到这些状态来要求经过身份验证/授权的用户.在这里,我们将资源限制为管理员:

.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角色成员的状态.我们讨论过的所有授权内容都将从那里开始.

Javascript相关问答推荐

JavaScript寻求、寻求和时间更新事件||Mux

使脚本兼容于其他YouTube URL格式

v-textfield的规则找不到数据中声明的元素

Vue-Router渲染组件但不更改网址

带对角线分隔符的图像滑动器

Fastify错误:CORS策略已阻止从起源api-dev.example.com上的MLhttp请求

fetch在本地设置相同来源的cookie,但部署时相同的代码不会设置cookie

使用axios.获取实时服务器时的404响应

通过在页面上滚动来移动滚动条

如何解决CORS政策的问题

使搜索栏更改语言

如何将Map字符串,布尔值转换为{key:string;value:bo布尔值;}[]?<>

在拖放时阻止文件打开

如何将Openjphjs与next.js一起使用?

阿波罗返回的数据错误,但在网络判断器中是正确的

如何在ASP.NET中使用Google Charts API JavaScript将条形图标签显示为绝对值而不是负值

如何将数组用作复合函数参数?

使用Nuxt Apollo在Piniastore 中获取产品细节

让chart.js饼图中的一个切片变厚?

如何限制显示在分页中的可见页面的数量