ui router onEnter中的访问范围或服务以检查访问权限(auth)

时间:2013-10-13 18:48:16

标签: angularjs angular-ui-router

好的,所以我有一个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");

我认为当前的选项是使用resolve和/或检查控制器中的身份验证。但是不能将auth检查更好地放在onEnter上吗?

6 个答案:

答案 0 :(得分:15)

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

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

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

  1. 使用OnEnter:

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

    • 对安全检查的状态的管理将与$ stateProvider.state()定义分开。理想情况下,我宁愿在一个地方看到关于状态定义的所有内容。虽然这不是一个表明,但它并不理想。
    • 更大的问题是没有为初始加载页面调用$ stateChangeStart事件。这是一个表明。
  3. 我的解决方案是使用resolve函数来定义一个promise,它将导致视图控制器在调用之前等待延迟完成。这非常适合阻止控制器以异步方式启动。

    这是我使用的代码的大致轮廓:

    .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);
    
    }]);
    

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

答案 1 :(得分: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是否有与身份验证相关的属性等。

答案 2 :(得分:7)

从github页面查看此issuethis示例。它应该给你一些线索。

答案 3 :(得分: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将令牌存储在本地存储上,而ngStorage提供了$ localStorage服务,我在注入onEnter的Auth工厂注入了

答案 4 :(得分:-1)

可能你的意思是

<td>  
<asp:TextBox ID="TextBox1" runat="server" AutoPostBack="True"OnTextChanged="TextBox1_TextChanged"></asp:TextBox>  
<asp:AutoCompleteExtender ServiceMethod="GetCompletionList" MinimumPrefixLength="1"  
   CompletionInterval="10" EnableCaching="false" CompletionSetCount="1" TargetControlID="TextBox1"  
   ID="AutoCompleteExtender1" runat="server" FirstRowSelected="false">  
      </asp:AutoCompleteExtender>  

答案 5 :(得分:-3)

我正在使用angularjs 1.3和ui.router 0.2.10

我确定自从提出这个问题以来已经发生了很多变化,但我必须自己解决这个问题并且我的搜索引导我来到这里......

就检查身份验证而言,你可以这样做

.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(&#39; $ stateChangeStart&#39;,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,也许有人可以扩展它。