How to authenticate and automatically redirect to login state using ui-router?

so i have this function in mine run

in angularjs (AngularJS v1.2.26 is running)

.run(function(....) {
    authService.authCheck();

    $rootScope.$on('$routeChangeStart', function(event, next, current) {
        if (next.requireLogin) {
            if (!authService.isLoggedIn()) {
                $location.path('/login');
                event.preventDefault();
            }
        }
    });

})...

      

when directly accessing a url that requires authentication, eg. http://127.0.0.1:8080/secret

, the function always redirects the login path, explicitly after debugging it for a while, when it constantly evaluates to false. when accessing the default page, then jumping to the specified route is done without any problem.

This is part of my authService

this.authCheck = function() {
    $http({
        method: 'PUT',
        url: '/api/login'
    }).
    success(function(data, status, headers, config) {
        if (status === 200) {
            userIsAuthenticated = true;
        } else {
            userIsAuthenticated = false;
        }
        $rootScope.loginStatus = userIsAuthenticated;
    }).
    error(function(data, status, headers, config) {
        userIsAuthenticated = false;
        $rootScope.loginStatus = userIsAuthenticated;
    });
};

this.isLoggedIn = function() {
    return userIsAuthenticated;
};

      

This way, every time I have a breakpoint on !authService.isLoggedIn()

, I can see that it evaluates to false, even if the function in the startup block tries to authenticate it before the function reaches $rootScope.$on

.

What exactly prevents the persistence of a variable's state userIsAuthenticated

?

+3


source to share


2 answers


.authCheck

.authCheck

is asynchronous, which means userIsAuthenticated

it will not be set to true until it completes the first time. If you have followed the route you are currently on, you will have to write some more complicated code to wait if the check has not yet completed and then redirects. However, this is a dirty suboptimal option.

The best way to do this is to let it ui-router

be done for you. Create a shared ancestor state for all of your states that require a login, for example. 'session'

... Then do this state permission for authentication with option resolve

. If not authenticated, throw a specific state transfer failure error that you can catch elsewhere and act (redirect to login).

.state('session', {
    resolve: {
        authentication: ['authService', '$q', function (authService, $q) {
            return authService.checkAuthentication().then(function () {
                if (!authService.isAuthenticated) {
                    return $q.reject({
                        notAuthenticated: true
                    });
                }
            });
        }]
    },
    // ...
})
.state('secret', {
    parent: 'session',
    // ...
});

      

and then



$rootScope.$on('$stateChangeError', function (_0, _1, _2, _3, _4, error) {
    if (error.notAuthenticated) {
        $state.go('login');
    }
});

      

(you will also need to correctly return from authentication)

checkAuthentication: function () {
    return $http({...})
        .success(...)
        .error(...);
}

      

+6


source


Have you allowed the app to send a request from / secret? This can prevent you from submitting any request from there so that it will redirect you to login



0


source







All Articles