randombits
randombits

Reputation: 48490

Best practice for ensure user is logged in or out using cookieStore and AngularJS

Right now I am building an AngularJS based application on top of Ruby on Rails and using Devise for authentication. I have the server responding properly when a user authenticates successfully and when authentication fails. I guess my question is, using $cookieStore, what's the best practice for knowing if a user is logged in or not? There is a cookie that gets set by Rails called "myapp_session", but that session doesn't necessarily mean a user is logged in. Looking for ideas on how to use AngularJS to keep user online/offline management. I'll still be ensuring that requests that require authorization get authorized by the backend regardless of the solution.

Upvotes: 22

Views: 30946

Answers (3)

Maciej Gurban
Maciej Gurban

Reputation: 5739

If you're having problems making the accepted answer work, be wary, that as of Angular 1.3, a proper way of adding a new interceptor is by adding it to $httpProvider.interceptors, so instead of:

$httpProvider.responseInterceptors.push(interceptor);

use:

$httpProvider.interceptors.push(interceptor);

Upvotes: 2

Zack Argyle
Zack Argyle

Reputation: 8427

You can set the cookie on your login callback with

$cookieStore.put('logged-in', some_value)

Then check for it when they enter your site with

.run(function($cookieStore) {
    if ($cookieStore.get('logged-in') === some_value) {
        let him enter
    }
    else {
        you shall not pass
    }
});

There might be more "correct" ways, but this works.

Upvotes: 4

Deividi Cavarzan
Deividi Cavarzan

Reputation: 10110

You can create an directive that set up the logged user when the application loads, for example, requesting the current user session on your server.

angular.module('Auth', [
        'ngCookies'
    ])
    .factory('Auth', ['$cookieStore', function ($cookieStore) {

        var _user = {};

        return {

            user : _user,

            set: function (_user) {
                // you can retrive a user setted from another page, like login sucessful page.
                existing_cookie_user = $cookieStore.get('current.user');
                _user =  _user || existing_cookie_user;
                $cookieStore.put('current.user', _user);
            },

            remove: function () {
                $cookieStore.remove('current.user', _user);
            }
        };
    }])
;

And set in your run method in AppController:

   .run(['Auth', 'UserRestService', function run(Auth, UserRestService) {

            var _user = UserRestService.requestCurrentUser();
            Auth.set(_user);
        }])

Of course if any request to the server return an Http Status 401 - Unauthorized, you need to call the Auth.remove() service to remove the user from cookie and redirect the user to login page.

I use this approach and works very well. You can also use the localStorage, but the user data will be persisted for a long time. Unless you set an expiration date for this authentication, I don't see as best practice.

Keep in mind to always verify the user credentials on your server site =)

[EDIT]

To listen to 401 - Unauthorized server response, you can put an interceptor on your $http request, like this:

 .config(['$urlRouterProvider', '$routeProvider', '$locationProvider', '$httpProvider', function ($urlRouterProvider, $routeProvider, $locationProvider, $httpProvider) {
        $urlRouterProvider.otherwise('/home');
        var interceptor = ['$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);
            };
        }];

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

Every call with 401 response, the user will be redirected to login page at /login path.

You will find a good example here

Upvotes: 37

Related Questions