1

I'm trying to implement basic authentication routing in AngularJS. I have a model that has a authorize method that returns a promise. I want the routing to wait until that authorize function has returned true or false to continue, once that has completed it should resume the path or redirect the user to the login page.

I think essentially i need to stop routing, call that method and then resume or redirect to login. Below is the code I have so far but i'm not sure how to accomplish the pause/resume. Any ideas?

return angular.module('d', ['ngCookies', 'ngRoute'])
    .config(['$routeProvider', '$locationProvider', '$httpProvider', 
        function ($routeProvider, $locationProvider, $httpProvider) {

            $routeProvider.when('/',
            {
                templateUrl: 'views/home.html',
                controller: 'HomeCtrl'
            });
            $routeProvider.when('/login',
            {
                templateUrl: 'views/login.html',
                controller: 'LoginCtrl'
            });

            $routeProvider.otherwise({ redirectTo: '/404' });
            $locationProvider.html5Mode(true);

            // handle unauthorized requests by redirecting to login page
            $httpProvider.responseInterceptors.push(
                ['$location', '$q', function ($location, $q) {
                    function success(response) {
                        return response;
                    }

                    function error(response) {
                        if (response.status === 401) {
                            $location.path('/login');
                            return $q.reject(response);
                        }
                        else {
                            return $q.reject(response);
                        }
                    }

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

        }])
    .run(['$rootScope', '$location', 'Auth', function ($rootScope, $location, Auth) {

        $rootScope.$on("$routeChangeStart", function (event, next, current) {
            $rootScope.error = null;
            Auth.authorize().then(function(){
                $location.path('/');
            },function(){
                $location.path('/login');
            });
        });

    }]);
2
  • [$routeProvider resolve][1] is the correct approach I feel. [1]: stackoverflow.com/questions/18788586/… Commented Nov 5, 2013 at 20:49
  • Could you provide the ´authorize´ method please Commented May 14, 2014 at 11:54

1 Answer 1

2

Your solution is very similar to a prototype I wrote a while back.

The idea is that whenever you "touch" the server and get an authentication error, a modal window pops-up asking for a login without changing the URL (you let it change to the new URL and stay there).

My implementation was also based on an interceptor checking for 401. It has a dependency on $rootScope and sets a property "needsLogin" to true. The page template has the login modal window visible when needsLogin === true and hides the ng-view (this is important since the new route has been loaded but it misses its data). Finally, upon successfull login, the login controller does the $route.reload() and then sets $rootScope.needsLogin = false.

Small snippets:

<div id="main" role="main" ng-show="needsLogin === false">
    <div ng-view></div>
</div>

<div ng-show="needsLogin === true" ng-include="'views/login.html'" class="overlay"></div>

The login controller can be something like:

function LoginCtrl($scope, $rootScope, $route, $http) {

    $scope.login = function () {
        $http.post( /* Somehow do your login */ )
            .success(function () {
                var deregister = $rootScope.$on('$routeChangeSuccess', function () {
                    // hide login / show ng-view after route has been reloaded
                    $rootScope.needsLogin = false;
                    deregister();
                });
                $route.reload();
            })
            .error(function () {
                /* handle errors */
            });
    };
}

$route.reload() is not a full page refresh, it merely re-initializes the route (controller/view etc). Hopefully, the call that was rejected before will run again and the page will be fine.

Sign up to request clarification or add additional context in comments.

2 Comments

I like your idea about the dropping the modal over the top to better preserve the URL, in code I did not show in this sample I cached the url and then redirected upon success. I'm scared with this approach I might get a ton of errors before I get that dialog due to failures via the service auth.
I found this gist.github.com/thomasnordlund/4025773 but it seems over complicated.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.