In the process of developing an Angular 4 CMS with Flat Files I knew I needed some sort of authentication to enable administrators to login to special areas to edit the content that is within JSON files. In the regard, I may have lied a little bit, as we do still need server side code in order to do proper authentication. You could set up a whole database or use other backends, but I wanted to keep it extremely simple and continue on with the flat file idea by using PHP. PHP can be run on even shared webhosts like Namecheap, whereas .NET and Python typically require something like a VPS set up. Below you can see the full plan for what we will create over a series of posts, starting in this post with the authentication piece which is one of the more difficult aspects:
The following is a rough outline for what we will cover in this post. Once complete you will have a barebones authentication service with Angular 4 that can be run on any server, even shared hosting.
- Server Side Authentication with PHP
- Angular4 Auth Service
- Login Page
- Restricted/Unrestricted Components
- AuthGuard Routing with CanActivate
To see this barebones authentication in action, head to http://acostanza.com/php-angular-auth. You should be redirected to /unrestricted/ and see the following content:
If you click the link, it attempts to route you to /restricted/ but sees that you do not have login privileges. It presents the login page to pass credentials to our PHP authentication service.
I included a piece below that shows this form is an Angular form that submits the username and password asynchronously to the PHP authentication service. Login using the credentials you see below:
Hit submit and you are brought to the restricted route at /restricted/:
Pretty simple. Using this barebones example you can have as many restricted routes to administrative components as you’d like that are accessible via a login page.
Server Side Authentication Details
- Contains JSON encoded user,pass pairs with passwords encoded with PHP’s password_hash()
- Saved into a PHP variable to ensure no access is granted client-side
- if auth == 0, not authenticated
- if auth == 1, authenticated for admin CMS pages
- return(user:string OR none, auth:int)
- same auth rules as above
- return(user:string OR none, auth:int)
Put the following into auth.php:
This does all of the authentication work on the server side. It opens the users.php file (described below) and grabs the json encoded usernames and hashed passwords that are stored in a PHP variable. I like storing it in a PHP variable because that means the data is not available client side, but can be easily loaded and updated on the server.
Now put the following in users.php:
This has only one user, adam with the hashed password tacos, as described above in the Demo. You can generate your own JSON object of a user using this PHP code:
Angular 4 AuthService
In order to check if we are authorized, we need an Angular Service that will check the auth.php file using the HttpClient to tell the application if the user is authenticated. The AuthService must be able to POST a username and password and receive a 0 or 1 for authorization and also GET the page without credentials after authentication. You could store a variable in the localStorage but I feel like it is better to have the server indicate whether the user is authenticated rather than the vulnerable front-end memory.
Here is what I have written for my simple AuthService, put it in auth.service.ts:
Above you can see two different methods, login(user,pass) and checkAuth(). They both return Observable<boolean> because they implement the aysnchronous HttpClient method. Observables can be mapped, for example the above code maps the JSON response ‘auth’ == 1 to true and else to false. The reason to return the user data is that it may be used in an administrative area and passed on to a local variable, but in this case we do not actually use it.
Now that we have an AuthService, let’s create a component that can be accessed by anyone and a component that can only be accessed after a login and authorization check.
Let’s start with the unrestricted component, basically the default one that is created by ng new <project-name>. Put the following in app.component.ts:
And the following in app.component.html:
This provides the basic unrestricted page with a link to /restricted/ which we will protect via our AuthGuard later. See below for the code for the restricted route, not much is different except the HTML:
And in restricted.component.html:
As you can see, there isn’t anything super exciting in this component. But you could make this be an administrative console, or restricted components could also have areas to edit content from either a flat file storage solution or a database.
We also need a login page now that we can redirect an unauthorized user to in order to put credentials in to verify against the server. For this example I used a simple bootstrap login that I found. I modified the HTML code to make it work with Angular’s Form module using a template driven model.
Save this into login.html:
Make sure you also save the css code from here into login.css
Component with AuthService
Now that the basic form is set up, we need to set up the login component which injects the AuthService to check user credentials against the server. When the login page is encountered, the component should check if the user is already authorized and if so redirect to the restricted page (or administrative area). If the user is unauthorized the login form is displayed and the onSubmit method from the template-driven form is handled to post the user credentials against the PHP auth.php file.
Put the following code into admin.login.ts:
As you see, on initialization this component checks the PHP auth page without credentials to see if the login page is necessary. On submission of the form the username and password are posted to the auth page as well and redirection occurs if authorized. Note that the login actually subscribes to the Observable<boolean> provided by AuthService, because we want to get the boolean result from the Observable by subscribing to it, and only rerouting to the restricted area if the result of the Observable is true. If the result of the observable is false, we of course stay on the login page with no additional navigation.
AuthGuard Routing with CanActivate
Now that we have the components it is time to set up the routes. The previous components had routerLink which refers to a specific path. The routing for this is all done in app.module.ts:
Most of this is just like a typical module. It is the following portion of code where the Routes are defined including the AuthGuard for restricted routes:
The work is done through the canActivate property which calls AuthGuard. You can actually have multiple different AuthGuards for different routes. I also have a canActivateChild route which just links to the same component. I actually read a really interesting article by Netanel Basal about how you can implement componentless routes which essentially enables you to only have to list the canActivateChild property once and then have all protected routes under the parent route. Pretty cool stuff!
The very last thing we need to run this barebones authentication with PHP and Angular 4 is an index component.
The following goes in app.index.ts:
And the following into index.html:
And we are in business! One again, access the Demo here. You may have noticed there isn’t a logout, this can easily be done with an asynchronous request to a logout.php page that simply has <?php session_destroy(); ?> within it, but I didn’t really have a particular need for it here.