27

好的,所以我有一个 URL“/securepage”的状态,每当用户尝试访问它时我都需要检查它。所以我读到有一个我可以使用的 onEnter 函数。但我似乎无法从那里获得范围或服务。我究竟做错了什么?

        .state('securepage', {
            url: "/securepage",
            template: securepage.html,
            onEnter: function(){
                // if (!$scope.main.isAuthenticated) $state.go("/login");
                // if (!myLoginService.currentUser()) $state.go("/login");

我看到的当前选项是使用解析和/或检查控制器中的身份验证。但是在 onEnter 中放置身份验证检查不是更好吗?

4

6 回答 6

15

我今天遇到了类似的问题。花了一整天的时间,终于想出了一个可行的解决方案,而不是这里已经建议的解决方案。

我的主要目标是找到简单有效的方法来选择性地保护某些特定网页。需要在加载或调用 HTML 或任何相关控制器之前执行安全检查。如果检查失败,页面可能会被转发到其他地方,而不会受到其他控制器的任何副作用。

我尝试了其他建议的方法。每个人都有自己的一系列问题:

  1. 使用 OnEnter:

    • 在进行异步调用以进行安全检查时,无法阻止 ui-router 继续状态转换。
  2. 使用 $rootScope.$on('$stateChangeStart'):

    • 需要安全检查的状态的管理将与 $stateProvider.state() 定义分开。理想情况下,我宁愿在一个地方看到关于状态定义的所有内容。虽然这不是一个炫耀,但它并不理想。
    • 一个更大的问题是没有调用 $stateChangeStart 事件来进行页面的初始加载。这是一个展示者。

我的解决方案是使用一个解析函数来定义一个承诺,这将导致视图控制器在调用它们之前等待延迟完成。这非常适合阻止控制器以异步方式启动。

这是我使用的代码的粗略轮廓:

.config(['$stateProvider', function ($stateProvider) {
    // Handler for Restricting Access to a page using the state.resolve call
    var accessRestrictionHandler = function($q, $rootScope, $state) {
            var deferred = $q.defer();

            // make sure user is logged in
            asyncCheckForLogin(function(status) {
                if (status != "Logged In") {
                    // You may save target page URL in cookie for use after login successful later
                    // To get the relative target URL, it is equal to ("#" + this.url).  
                    //      The "this" here is the current scope for the parent state structure of the resolve call.
                    $state.go("loginPage");
                }
                else    // if logged in, continue to load the controllers.  Controllers should not start till resolve() is called.
                    deferred.resolve();
            }.bind(this));

            return deferred.promise;
        };


    $stateProvider
        .state('userProfile', {
            url: '/userProfile',
            views: {
                'main': {
                    templateUrl: 'userProfile.html',
                    controller: 'userProfileCtrl'
                }
            },

            // SIMPLY add the line below to all states that you want to secure
            resolve: { loginRequired : accessRestrictionHandler } 
        })

        .state(.... some other state)
        .state(.... some other state);

}]);

我希望这会对你们中的一些人有所帮助。

于 2014-08-18T16:07:11.573 回答
14

另一种方法是让服务/控制器监听“$stateChangeStart”事件。在那里,您可以检查被调用状态是否需要身份验证并重新路由请求。这是一个片段:

$rootScope.$on('$stateChangeStart', function (event, nextState, currentState) {
    if (!isAuthenticated(nextState)) {
        console.debug('Could not change route! Not authenticated!');
        $rootScope.$broadcast('$stateChangeError');
        event.preventDefault();
        $state.go('login');
    }
});

isAuthenticated可以保持对您的服务的调用,检查nextState.data与身份验证相关的属性等。

于 2013-10-14T14:25:07.127 回答
7

从他们的 github 页面查看这个问题这个例子。它应该给你一些线索。

于 2013-10-14T09:34:02.130 回答
0

一个迟到的答案,但无论如何我宁愿写它。我宁愿尽可能不碰 $rootScope。这是我目前正在处理的代码,它总结了您问题的另一个解决方案:

state('dash', {
                url:'/',
                views:{
                    "topNav":{
                        templateUrl:"user/dash/partials/top-nav.html",
                        controller:'logoutCtrl',
                    },
                    "sideNav":{
                        templateUrl:"user/dash/partials/side-nav.html"
                    },
                    "body":{
                        templateUrl:"user/dash/partials/body.html",
                        controller:'testCtrl'
                    }
                },
                onEnter: function(Auth, $state){
                    if(!AuthSvc.isAuthenticated){
                        $state.go('login');
                    }
                }
            })

我正在使用 JWT 通过使用 ngStorage 将令牌存储在本地存储中,该服务提供了一个 $localStorage 服务,我将其注入到我在 onEnter 中注入的 Auth 工厂中

于 2016-10-29T11:57:03.707 回答
-1

可能你的意思是

.state('securepage', {
        url: "/securepage",
        template: securepage.html,
        //this is how you actually inject things to onEnter property
        onEnter: ['$state','myLoginService',function($state,myLoginService){
             if (!$scope.main.isAuthenticated) $state.go("/login");
             if (!myLoginService.currentUser()) $state.go("/login");`}]
         ....
于 2015-06-19T14:16:28.560 回答
-3

我正在使用带有 ui.router 0.2.10 的 angularjs 1.3

我敢肯定,自从提出这个问题以来已经发生了很多变化,但是因为我必须自己弄清楚,我的搜索把我带到了这里......

至于检查身份验证,你可以这样做

.state('securepage', {
        url: "/securepage",
        template: securepage.html,
        onEnter: function($scope,$state,myLoginService){ //THIS IS THE CHANGE
            if (!$scope.main.isAuthenticated) $state.go("/login");
            if (!myLoginService.currentUser()) $state.go("/login");

您可以在 onEnter 函数中放置相当多的提供程序/服务/工厂来访问它,这在应用程序的 .config 内部确实有效。

话虽如此,他们(ui-router 制造商)建议使用自定义规则函数在 .$on('$stateChangeStart', function(e, to) https://github.com/angular-ui/ui-router中处理它/wiki/Frequently-Asked-Questions#how-to-create-rules-to-prevent-access-to-a-state 我不知道他们为什么这样做而不是 onEnter,也许有人可以对此进行扩展。

于 2014-06-28T14:06:06.687 回答