Auth Service

First and foremost, we need to create an Authetication Service which will wrap all of Auth related states and actions in one place, in particular login/logout actions and user authentication status (user is logged in/out), and all off it asynchronously as a stream (brace yourselves RxJS is incoming).

ng g s services/auth

s = service

This is our authentication service (./src/app/services/auth.service.ts):

Looks intimidating at first glance, but trust me, there is nothing complicated, so let’s break it down:

Line 9: userSignedIn$ is a RxJs Subject (of type boolean), which means it is an Observer and an Observable at the same time, which means we can control its value in our service, and observe its changes outside of it.

Our constructor will initialize the login state by using TokenService’s validateToken() method, which will validate current token (if exists) against the Rails backend, this operation is asynchronous and returns in its body an object that looks like this:

So we can use success key to determine wether the user is logged in with a valid token or not (line 14).

Dollar sign ($) at the end of the name is a convention to specify that this is not a simple variable, but an observable stream of data which changes in time.

Our logOutUser() method takes no params and returns an Observable of Response , we’ll call signOut() on Angular2TokenService , but before returning its response, we’ll map though it to change userSignedIn$ value to false (line 19) in order to notify our observers that user successfully logged out, and then return the response to whomever is observing the result of logOutUser() method (line 20).

method takes no params and returns an , we’ll call on , but before returning its response, we’ll map though it to change value to (line 19) in order to notify our observers that user successfully logged out, and then return the response to whomever is observing the result of method (line 20). The logInUser method takes an object with email and password keys, and uses it to sign in from Angular2TokenService signIn() method. And again, before returning the response we will modify userSignedIn$ value to true, which will notify the observers that user logged in successfully .

method takes an object with email and password keys, and uses it to sign in from Angular2TokenService signIn() method. And again, before returning the response we will modify value to which will notify the observers that user logged in successfully The registerUser method is similar to loginUser, but we have an additional password confirmation attribute in the input object.

Let’s not forget to inject it into our main AppModule’s providers (./src/app/app.module.ts):

... import {AuthService} from "./services/auth.service"; @NgModule({

declarations: [

AppComponent,

HomeComponent,

ToolbarComponent,

AuthDialogComponent,

LoginFormComponent,

RegisterFormComponent,

ProfileComponent

],

imports: [

BrowserModule,

FormsModule,

HttpModule,

AppRoutingModule,

MaterializeModule,

],

providers: [ Angular2TokenService, AuthService],

bootstrap: [AppComponent]

})

export class AppModule { }

Refactoring Login and Toolbar components to use AuthService

Now we need to make some small changes to our Login and Toolbar components in order to use AuthService instead of Angular2TokenService directly.

Refactoring the Toolbar

Let’s start with ToolBarComponent class (./src/app/toolbar/toolbar.component.ts):

As you can see, we got rid of Angular2TokenService and injected our custom AuthService instead (line 16), we also created a logOut() method which will call logOutUser action on our AuthService, and using Angular Router, redirect the user to home when logout action completes (line 21).

Now let’s change Toolbar’s template (./src/app/toolbar/toolbar.component.html):

Now we are using our AuthService’s userSignedIn$ Subject to change the state of the toolbar when user logs in or out, considering that userSignedIn$ is not a simple value, but an asynchrnous stream of values chaning in time, we need to use Angular’s async pipe to listen to its changes (lines 11, 12, 14, 15). We’ll also link the click event on logout button to toobar component’s logOut() method we created earlier (line 15).

Refactoring the Login From

Changes on login form will be extremely minimal, we just need to change the LoginFormComponent class (./src/app/login-form/login-form.component.ts)

The only thing we needed to do is getting rid of Angular2TokenService and replacing it with our AuthService and its logInUser method.

Don’t forget to apply the same changes to RegisterFormComponent

And that’s it, refactoring is over.

User profile page

Profile component

First step is obvious, let’s generate our ProfileComponent that will display current user’s info:

ng g c profile

The component should be automatically imported in AppModule’s declarations.

Profile route

In our router module (./src/app/app-routing.module.ts), let’s declare the profile route:

Import the profile component:

import {ProfileComponent} from "./profile/profile.component";

Declare the route:

... const routes: Routes = [

{

path: '',

component: HomeComponent,

pathMatch: 'full'

},

{

path: 'home',

component: HomeComponent

},

{

path: 'profile',

component: ProfileComponent

}

];

...

UI

As for the design of profile page, it’ll be pretty simple, we’ll display user’s email, name, and user name in a Materialize Card and use its footer to add a logout button.

Let’s inject Angular2TokenService into our ProfileComponent, and add a logout method (./app/profile/profile.component.ts):

We’ll be making use of Angular2TokenService to display user’s personal information, AuthService to implment the logout action, and the Router to redirect after logout completes, so we need to inject these in our ProfileComponent (lines 14–16)

Nn line 18, we have a logOut action which redirects the user to home when it completes.

Reimplementing the logOut action for each component seems repetitive, but this is actually useful, because we can implement different post-logout behaviours for each component, for example redirecting to some other route instead of home.

Profile Component’s template, (./src/app/profile/profile.component.html)

Angular2TokenService’s currentUserData attribute provides information about our user if he is logged in (email, name, nickname, etc.), its value is undefined when user is not logged in.

One line 15, we are usign *ngIf structural directive to test if there is any data to display, if not we will not show the user info card.

On line 31 we also have a logout button, linked to logOut method of our ProfileComponent class.

Be sure to add a cleafix class to ./src/app/profile/profile.component.sass because Materialize doesn’t implement it.

.clearfix

overflow: auto

And this is what we get when we navigate to /profile route while being logged in: