Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
  • Overview
  • Transcript

3.1 The Auth Service

So, far in our simple project management application, we have created a Projects page which lists all the projects in our application. Now, obviously, by looking at these projects, you can see that we have some concept of users. However, so far, we haven't created any system whereby users can log in and out. And so for the next couple of lessons, we're going to focus specifically on users and how they might interact with the system. This will include things like creating a login panel where users can log in, and of course, users will also be able to log out. And it will also include protecting certain routes, like our projects list here, because someone shouldn't be able to view a projects list unless they are logged in. So we're going to start by creating an authentication service. This service will not only manage users logging in and logging out, but it will also keep track of the currently logged in user so that we can use that user's name and details throughout the application. So in our app directory let's create a file called auth.service.ts. As we did with our project service, we will import both the Injectable decorator and we'll also import the Http class so that we can make requests to the server. We'll begin of course by calling the Injectable decorator. And then after that, we will export our class, and this class is going to be called the AuthService. Inside this class, we'll start by creating our constructor so that we can inject our Http class. So we will call private http and we'll use the Http class, and that will inject the Http instance for us. And now let's create a login function. And this is where the actual login will take place. This function will expect two parameters. It will take a username, which will be a string, and a password, which will also be a string. And it will return an Observable which wraps a boolean. Now, if we wanna use Observable like this, we'll have to import the Observable class. So up at the top here, let's go ahead and import observable from rxjs. All right. Now, in here, we will do this.http.post. We'll post to /api/login. And when we use the Http class's post function, we can pass the body of that post request as our second parameter. So let's just create an object here, and we will give it the username and the password. And we're using the ECMAScript 6 shortcut syntax there because the key and the value would be the exact same thing, username username, password password. So, just like with the HTTP get method, HTTP post returns an Observable. And so we're going to map this Observable. We'll map the response inside the Observable to the object that is returned. And then we'll map again, and the object that will be returned this time is the user object itself. Now, it will be the user object if this username and password was successfully logged in. However, if these were wrong, the response will be null, and so the user object here will be null. So in here, let's say if user. And then of course, inside this if block, we know that there actually was a user logged in. Now, we're going to keep track of the logged in user using local storage. So this way, when they refresh their page, they won't have to log in if they have already been logged in. So we'll say localStorage.setItem, and we will set the user key. And we can just do JSON.stringify(user). Of course, local storage only accepts strings and not objects. So we'll just have to convert that user object to a string. Now, there's something else that we need to take care of inside this if block, but that requires a little bit of setup up here in our AuthService. We're going to use another Observable to keep track of the current user. Different parts of our application will be able to subscribe to that Observable to keep track of whether the user is logged in or logged out. And we're going to create a type of Observable called current user. So the Observable type that we want to use is called a behavior subject. Now, this is also part of rxjs. So let's go ahead and import the BehaviorSubject class. If you're not familiar with Observables, what you need to know is that Observables can be observed by an observer. So, there are two classes going on there, the Observable and the Observer. Now, the subject is just both an Observable and an Observer. So when you're working with a, subject one part of the code could be the Observer and read values off that subject, and the other part of the code could be the Observable and actually publish values. Of course, our authentication service here will be the observable part, where it's going to be publishing values. And then we'll see later on in our code how other parts use our behavior subject from the observer point of view where they are reading data. The behavior part of the subject just means that whatever the last value that was published to this subject was will be saved in the subject. And whenever someone new subscribes to the subject, they'll immediately get whatever the last value was. And that's exactly what we want. Whenever someone new subscribes to the current user, they'll immediately get whatever the last published value was as well as being subscribed to any new changes. So at the top of our authentication service here, let's create a currentUser property, and this is going to be a BehaviorSubject. And we'll instantiate this right away, we'll say new BehaviorSubject. And we need to pass the initial value as the first parameter here to the BehaviorSubject constructor. So we'll just say false, meaning that there is no current user. So now, back inside of login, if the user was logged in, then not only do we need to save that value in local storage, we also need to publish that value to the current user stream. So we'll say this.currentUser.next, and that will equal the user object. So this way if any parts of our code are listening or subscribed to the current user subject, when we call currentUser.next, we're pushing a new value into that stream and those listeners at the other end will get that value back. Now, we said that this login method needs to return an Observable that wraps a boolean. So at the end of our last map call here, let's return !!user. And what this will do is convert our user object here to a boolean. As you probably know, one exclamation point returns the opposite boolean value of whatever this is. So two just negates it again but makes sure it's a boolean value. So if user is null, two exclamation points will return false. But if user is an object, two explanation points will make this return true. Of course, we have to return at the top of this function where we make our call to HTTP post. And now we have a successful login method. Now, there are a few other methods we'll need here. Let's create a getUser method, which will just return the user object from local storage. So what we can do is say var user = localStorage.getItem(user). Now, it's possible we're trying to get a user that is not there. So if there is a user value, we'll do JSON.parse(user), otherwise we'll just return false. Okay, now, there's something else to consider. Let's say the user has logged in previously and so their user information is stored in localStorage. But then they leave the site for a while, and then they come back. Well, they've already been logged in. So when our authentication service here initializes, we need to take note of that. Well, we can do that within the constructor here. Within the constructor, we will do this.currentUser to get our BehaviorSubject, and we will publish a new value here. And we can just publish whatever value is within local storage. So if there is a user in there, we'll publish their user object, just like we would when they log in. Otherwise, we'll just publish false. Well, we just wrote a function that does exactly this, getUser. So what we can do here is say this.currentUser.next, and we can publish this.getUser. We also need a logout function. The logout function will be very basic, it has two responsibilities. First, it has to remove the user from local storage. So we'll say localStorage.removeItem('user'). And then we can say this.currentUser.next equals false. All right, we need one more function, we'll put this at the bottom. And this will just return a boolean isLoggedIn. This won't return an Observable or do anything fancy, it's just going to return a plain old boolean, is a user logged in or not. And in here, we can just do the same double exclamation point trick and say this.getuser. So there we have our finished authentication service. The last step for this lesson is to add our AuthService here to our app module. But not in the way that you might expect. We'll of course begin by importing it. We'll import the AuthService from auth.service. However, we don't need to add it to our declarations right here, because that's not what we do with services. However, instead, we are going to add a providers array here. Now, you probably remember seeing the providers array before. If we open up the project's component, you might remember that when we wanted Angular's dependency injection to inject the ProjectsService object into our ProjectsComponent, we had to add a providers array here to the component listing the classes that would need to be injected. And we can do this in multiple components, and every component will get its own object of ProjectService. However, we can't do the same thing with AuthService. And that's because we need to use the same AuthService object in multiple components. For example, if we come back to our browser here. Eventually we're going to have a log in component which is where the user will log in. And of course, they will use the AuthService there to perform the log in. However, our toolbar up at the top here is part of the app component. And we want eventually to display the name of the logged in user there. And so this component will also use the AuthService. But if they each have their own AuthService, instance then they'll have different current user observable objects, and so they won't be able to share the information. By providing the AuthService class at a module level instead of at the component level, we can make sure that every component will use the same one AuthService object and they'll all have access to the same observable stream. All right, so that's it for our authentication service. Now let's focus on some user interfaces that the user can use to log in.

Back to the top