質問

So I'm doing a simple 'is the user logged in' check and redirecting the user to the signin.html page if they are not logged in. My code looks something like this:

var myAppModule = angular.module('myApp', ['ngRoute', 'ngCookies']);

myAppModule.config(function($routeProvider) {
$routeProvider
.when('/page2', {
    controller:'pagetwo',
    templateUrl:'pagetwo.html'
})
.when('/signin', {
    controller:'signinCTRL',
    templateUrl:'signin.html'
})

});

myAppModule.run(function($rootScope, userInfo, $location) {
$rootScope.$on('$routeChangeSuccess', function () {
    myCurrentRoute = $location.$$path;

    if(myCurrentRoute != "/signin") {
        userInfo.checkLogin(); //  Check login first. This has the $location.path( "/signin" ); in it.
    }
})

});

My problem is that when a user goes to /page2, the $routeChangeSuccess function fires fine and inside the userInfo.checkLogin() I redirect them to a new route that redirects them on the signin.html page.

The problem is that the pagetwo controller still fires before the user is redirected to the signinCTRL controller.

Is there a way to prevent the pagetwo controller from running somehow? I know I could probably just wrap everything in the signinCTRL to check if the user is logged in, but that defeats the purpose of having the routeChangeSuccess function.

役に立ちましたか?

解決

Instead of watching for the $routeChangeSuccess you can watch for the $locationChangeStart event.

$locationChangeStart is fired before the controller is called.

You can read more about the differences between $locationChangeStart and $routeChangeStart in this blog on how to cancel route navigation in angular

demo plunker using $locationChangeStart

他のヒント

I have dealt with this very issue where the login feature was handled by a servlet outside of my angular js application.

I controlled access to the application through a javax.servlet.Filter

and I also had another Filter that I used on all Json requests coming from the application.

For the unauthenticated user scenario the Json filter behaved as follows;

 httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED); //401

I added a $rootScope method that forced login for any 401 response from a JSON controller.

   $rootScope.handleHttpFailure = function(data,status) {
        if (401 == status) {
            document.location.reload(true);
        }  else {
            console.log("post ERROR status:" + status + " response:" + data);
            $rootScope.alert('Error received status:'+ status + " response:" + data );
        }
    }

So for your scenario, you can't prevent the pagetwo controller from running but you can prevent it from accessing secured resources if you follow this fairly simple pattern.

Listening to $routeChangeStart instead of the $routeChangeSuccess event might solve your problem in the short term. You can also do the login check in a one of the route resolve map promises and just return a promise dismiss for a login failure. then listening to the $routeChangeError could navigate for the signin url or just navigate to it from the resolve promise.

for a more complete and rubust routing solution you should probably use ui-router, the router any serious angular app should use (and is rumored to enter angular core in the future).

Yes, you should also validate correct login and authorization on the server side and return a 401 response in case It's invalid (then you can use the wonderful http auth interceptor to handle errors. But I disagree with the notion you should do it only server side, this is prone to lousy user exprience and you should certainly do the basic tests in the client side

Here is the best way to handle the error and works nicely

function ($routeProvider, $locationProvider, $httpProvider) {
    var interceptor = [
        '$rootScope', '$q', function (scope, $q) {

            function success(response) {
                return response;
            }

            function error(response) {
                var status = response.status;

                if (status == 401) {
                    var deferred = $q.defer();
                    var req = {
                        config: response.config,
                        deferred: deferred
                    };
                    window.location = "/";
                }

                if (status == 404) {
                    var deferred = $q.defer();
                    var req = {
                        config: response.config,
                        deferred: deferred
                    };
                    window.location = "#/404";
                }
                // otherwise
                //return $q.reject(response);
                window.location = "#/500";
            }

            return function (promise) {
                return promise.then(success, error);
            };

        }
    ];
    $httpProvider.responseInterceptors.push(interceptor);
});

// routes
app.config(function($routeProvider, $locationProvider) {
    $routeProvider
        .when('/404', {
            templateUrl: '/app/html/inserts/error404.html',
            controller: 'RouteCtrl'
        })
        .when('/500', {
            templateUrl: '/app/html/inserts/error404.html',
            controller: 'RouteCtrl'
        })

        ......

   };
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top