0

As of this post, I'm trying to figure out if the user is logged in (using a token based authentication).

The scheme is following :

1/ The page loads, app run is called, and authenticated is set to false as default

app.run(function($http, UserService) {
    UserService.requestCurrentUser();

    $http.defaults.xsrfHeaderName = 'X-CSRFToken';
    $http.defaults.xsrfCookieName = 'csrftoken';
});

app.constant('AUTHENTICATED', false);

2/ UserService call for its method requestCurrentUser() in which a http get is sent to the correct url with the token in its header.

  • If token is correct, this sends back the user (success case, we're authenticated).
  • If not, I get a permission error (error case, we're not authenticated).

This updates currentUserproperty and AUTHENTICATED constant.

app.factory('UserService', function ($http, $q, $window, AUTHENTICATED) {
    var _currentUser = {};

    return {
        
        getCurrentUser: function() {
            return _currentUser;
        },

        setCurrentUser: function(user) {
            _currentUser = user;
        },

        requestCurrentUser: function() {
            return $http.get('/accounts/api/').then(
                function (response) {
                    _currentUser = response.data;
                    AUTHENTICATED = true;
                },
                function (error) {
                    AUTHENTICATED = false;
                }
            );
        },
    };
});

3/ Controller is called and authenticated and currentUser scope values are updated.

app.controller('AuthCtrl', function ($scope, AuthService, UserService, AUTHENTICATED) {
    $scope.authenticated = AUTHENTICATED;
    $scope.currentUser = UserService.getCurrentUser();
});

Problem is that controller tries to reach the values before requestCurrentUser method (launched in app run) has received a response. So where should I launch requestCurrentUser to get the expected behavior ?

Thanks

Community
  • 1
  • 1
Ambroise Collon
  • 3,839
  • 3
  • 18
  • 37
  • strategy can be dependent on whether paths need to be blocked or not and which router is used. For example in ui-router a single parent state resolve can be used and all routes that require auth can be set as child states , none of which are accessible if parent resolve gets rejected. Other strategies include using route start event to resolve authentication – charlietfl Oct 23 '15 at 14:02
  • Lots of tutorials around on this subject – charlietfl Oct 23 '15 at 14:04
  • Any exemple of such tutorial ? Thanks ! – Ambroise Collon Oct 23 '15 at 14:12

1 Answers1

0

What you could do it wrap your user state object in a parent object. For example:

var state = {
    _currentUser: {}
};

return {
    getUserState: function(){ return state; }
};

Then inside your controller:

$scope.state = UserService.getUserState();

This way, when your user updates (no matter when or how in your service), anything bound to the state will receive the update. So your controller will have access to state._currentUser when it is available.

Matt Way
  • 32,319
  • 10
  • 79
  • 85
  • Thanks for your answer, as what I'm experiencing should be quite common, I'm wondering if there is a best practice for what I'm trying to achieve. I'm new on angular and I think that maybe I should rethink my structure more globally ? Maybe app.run() is not the place to request the current user. – Ambroise Collon Oct 23 '15 at 13:59
  • 1
    Having a service for managing your user state is a good choice. If you wrap the user in a container object, and wrap any async related processes in promises you should be good. That way you can inject your user service anywhere and do what you want with it. There are no specific standards for functionality layout like user auth, but you should be able to find plenty of examples. Keep experimenting and decide what is best for you. – Matt Way Oct 23 '15 at 15:21