Setting up authentication in angularjs

Before we can proceed to build the client-side sections, we’ll need to build the login and session management modules in angularjs. We’ll need to do this now, because the rest of the services for the CRUD operation are secured on the server side.

Creating our login page

We will start with the creation of our partial by creating a new file in angcms/public/partials/admin/login.html, and we will put in the following code:

<h1>Login</h1>
<hr/>

<form role="form" id="login" ng-submit="login(credentials)">

<div class="form-group">
<label>Login</label>

<input class="form-control" type="text" ng-model="credentials.username"/>
</div>
<div class="form-group">
<label>Password</label>
<input class="form-control" type="password"  ng-model=" credentials.password"/>
</div>

<input type="submit" class="btn btn-success" value="Login">
</div>
</form>

Next, we will create our controller in the angcms/public/js/controllers.js file with the following code.

  .controller('AdminLoginCtrl', ['$scope', '$location', '$cookies', 'AuthService','$log',
      function($scope, $location, $cookies, AuthService, $log) {
        $scope.credentials = {
          username: '',
          password: ''
        };
        $scope.login = function(credentials) {
          AuthService.login(credentials).then(
            function(res, err) {
              $cookies.loggedInUser = res.data;
              $location.path('/admin/pages');
            },
            function(err) {
              $log.log(err);
            });
          };
      }
  ])

You’ll notice that we have injected $location, AuthService, $scope, $log, and $cookies into our controller function.

angularjs has a module called ngCookies that allows to read and write to the browser cookie. However, this doesn’t come as a part of the angularjs library and needs to be included separately.

Run the following command in the terminal to download angular-cookies:

bower install angular-cookies

We’ll first need to load the angular-cookies.js file in our angcms/public/index.html file as follows:

<script type="text/javascript" src="bower_components/angular-cookies/angular-cookies.js"></script>

Next, we need to include the ngCookies module as a part of our main application. We do this in our angcms/public/js/app.js file, as highlighted in the following code:

angular.module('myApp', [
    'ngRoute',
    'myApp.filters',
    'myApp.services',
    'myApp.directives',
    'myApp.controllers',
    'ngCookies'
])

Next, we will create the AuthService factory that will contain the login and logout methods. Add the following code in the angcms/public/js/services.js file:

.factory('AuthService', ['$http', function($http) {
  return {
    login: function(credentials) {
      return $http.post('/api/login', credentials);
    },
    logout: function() {
      return $http.get('/api/logout');
    }
  };
}])

Let’s test our login functionality. Open the following URL in the browser, and log in with the correct username and password:

http://localhost:3000/admin/login

Using the correct username and password, you should get redirected to the pages listing.

Note

Make sure you have a couple of admin users saved; if not, use a REST API Client and create a couple of admin users using the following API URL:

http://localhost:3000/api/add-user

 

Setting up authentication in angularjs

Before we can proceed to build the client-side sections, we’ll need to build the login and session management modules in angularjs. We’ll need to do this now, because the rest of the services for the CRUD operation are secured on the server side.

Creating our login page

We will start with the creation of our partial by creating a new file in angcms/public/partials/admin/login.html, and we will put in the following code:

<h1>Login</h1>
<hr/>

<form role="form" id="login" ng-submit="login(credentials)">

<div class="form-group">
<label>Login</label>

<input class="form-control" type="text" ng-model="credentials.username"/>
</div>
<div class="form-group">
<label>Password</label>
<input class="form-control" type="password"  ng-model=" credentials.password"/>
</div>

<input type="submit" class="btn btn-success" value="Login">
</div>
</form>

Next, we will create our controller in the angcms/public/js/controllers.js file with the following code.

  .controller('AdminLoginCtrl', ['$scope', '$location', '$cookies', 'AuthService','$log',
      function($scope, $location, $cookies, AuthService, $log) {
        $scope.credentials = {
          username: '',
          password: ''
        };
        $scope.login = function(credentials) {
          AuthService.login(credentials).then(
            function(res, err) {
              $cookies.loggedInUser = res.data;
              $location.path('/admin/pages');
            },
            function(err) {
              $log.log(err);
            });
          };
      }
  ])

You’ll notice that we have injected $location, AuthService, $scope, $log, and $cookies into our controller function.

angularjs has a module called ngCookies that allows to read and write to the browser cookie. However, this doesn’t come as a part of the angularjs library and needs to be included separately.

Run the following command in the terminal to download angular-cookies:

bower install angular-cookies

We’ll first need to load the angular-cookies.js file in our angcms/public/index.html file as follows:

<script type="text/javascript" src="bower_components/angular-cookies/angular-cookies.js"></script>

Next, we need to include the ngCookies module as a part of our main application. We do this in our angcms/public/js/app.js file, as highlighted in the following code:

angular.module('myApp', [
    'ngRoute',
    'myApp.filters',
    'myApp.services',
    'myApp.directives',
    'myApp.controllers',
    'ngCookies'
])

Next, we will create the AuthService factory that will contain the login and logout methods. Add the following code in the angcms/public/js/services.js file:

.factory('AuthService', ['$http', function($http) {
  return {
    login: function(credentials) {
      return $http.post('/api/login', credentials);
    },
    logout: function() {
      return $http.get('/api/logout');
    }
  };
}])

Let’s test our login functionality. Open the following URL in the browser, and log in with the correct username and password:

http://localhost:3000/admin/login

Using the correct username and password, you should get redirected to the pages listing.

Note

Make sure you have a couple of admin users saved; if not, use a REST API Client and create a couple of admin users using the following API URL:

http://localhost:3000/api/add-user

Building a custom module for global notification

As you might have realized by now, our login page works fine as long as we put the correct credentials; however, when you try with an invalid username or password, the page doesn’t do anything.

Tip

The developer console should, however, show a 401 Unauthorized failed message.

We will need to build a notification system that displays a message when invalid credentials are passed. Thinking a few steps ahead, you’ll realize that we are going to need such messages displayed on many occasions, for example, when a new page has been created or updated, or when a page has been deleted.

In view of this, it is most ideal to build a global notification system that can be used all throughout our application.

angularjs allows us to create custom modules. These are self-contained modules that can be easily reused across multiple applications. A custom module is simply a wrapper that holds different parts of an angularjs app; these parts can be directives, services, filters, controllers, and so on.

As you would recall, ngCookies is a similar custom module we just made use of earlier.

Building and initializing the message.flash module

We will create a new file named message-flash.js at angcms/public/js/message-flash.js.

We will initialize it with the following code:

angular.module('message.flash', [])

We also need to include this in our app, so let’s include the message-flash.js file in our angcms/public/index.html file, as follows:

<script src="js/message-flash.js"></script>

Next, we add the message-flash.js file as a dependency in our main module in the angcms/public/js/app.js file, as highlighted in the following code:

angular.module('myApp', [
    'ngRoute',
    'myApp.filters',
    'myApp.services',
    'myApp.directives',
    'myApp.controllers',
    'ui.tinymce',
    'ngCookies',
    'message.flash'
])

Building the message.flash factory service

We will chain our factory to the message.flash module in our angcms/public/js/message-flash.js file, as highlighted in the following code:

angular.module('message.flash', [])
.factory('flashMessageService', ['$rootScope',function($rootScope) {
  var message = '';
  return {
    getMessage: function() {
      return message;
    },
    setMessage: function(newMessage) {
      message = newMessage;
    
}
  };
}])

The factory service is quite straightforward. We initialize a variable called message and have two methods, namely, setMessage and getMessage, which assign and read values to the message variable.

Setting up $broadcasts

Anybody who has tried to pass variables from one controller to another or to a directive would have realized that it isn’t quite straightforward, and one needs to use either rootScope or set up $watch or $digest to ensure that the scope objects update when the source has changed.

We will face a similar problem here where the message in our directive wouldn’t update when we pass the message from a controller.

To overcome this, we will set up $broadcast.

The broadcast, $broadcast, dispatches an event name to all child scopes. Child scopes use this as a trigger to execute different functions.

In our case, as we don’t really have a parent-child relation between the directive and our controllers, we will set up a broadcast on rootScope itself

We add the broadcast event to the setMessage method in the message-flash.js file as highlighted:

setMessage: function(newMessage) {
  message=newMessage;
  $rootScope.$broadcast('NEW_MESSAGE')
}

Now, every time the setMessage function is called, we will broadcast the event called ‘NEW_MESSAGE'.