Identity Server: Redirect When Route Requires Logged in User

This post is going to continue where the series on IdentityServer4 left off, but I am not officially making it part of the series. There may be a few posts like this where I improve on the example applications from the series. The starting code for this post can be found here.

All the changes in the post are in the Client Application from the sample linked above. I did some cleanup on a couple of files so if you are looking for the differences keep in mind most of the changes are a result of the cleanup.

Unauthorized Component

The first step is to add a new component that will be shown to the user when they navigate to a page that requires them to be logged in but they are not. Add a unauthorized.component.html file to the ClientApp/app/components/unauthorized/ directory with the following contents.

<h2>
    Login is required to access this area
</h2>
<div>
    <button type="button" 
            class="btn btn-primary" 
            (click)="login()">Login</button>
    <button type="button" 
            class="btn btn-default" 
            (click)="goback()">Back</button>
</div>

This will tell the user they need to log in and provide a login button and a button to go back to the previous page. Next, add a unauthorized.component.ts file to the same directory. This class will handle the clicks from the view.

import { Component, OnInit } from '@angular/core';
import { Location } from '@angular/common';
import { AuthService } from '../services/auth.service';

@Component({
    selector: 'app-unauthorized',
    templateUrl: 'unauthorized.component.html'
})
export class UnauthorizedComponent implements OnInit {

    constructor(private location: Location, private service: AuthService) {

    }

    ngOnInit() {
    }

    login() {
        this.service.startSigninMainWindow();
    }

    goback() {
        this.location.back();
    }
}

This class is using the AuthService for login and Angular’s Location class to move back to the previous page.

New Component Usage

Now that this new component exists it needs to set up in app.module.shared.ts. First, add an import.

import { UnauthorizedComponent } from './components/unauthorized/unauthorized.component';

Next, add to the declarations array.

declarations: [
    AppComponent,
    NavMenuComponent,
    CounterComponent,
    FetchDataComponent,
    HomeComponent,
    CallbackComponent,
    UnauthorizedComponent
]

Finally, add unauthorized to the routes array.

RouterModule.forRoot([
    { path: '', redirectTo: 'home', pathMatch: 'full' },
    { path: 'home', component: HomeComponent },
    { path: 'callback', component: CallbackComponent },
    { path: 'unauthorized', component: UnauthorizedComponent },
    { path: 'counter', component: CounterComponent },
    { path: 'fetch-data', component: FetchDataComponent, 
                          canActivate:[AuthGuardService]  },
    { path: '**', redirectTo: 'home' }
])

Now that this new component is in place how does it get used? Well, any route that has canActivate:[AuthGuardService] will require the user to be logged in to activate. For example, the fetch-data route above won’t activate unless the user is logged in.

Auth Guard Service

AuthGuardService is an existing class in the project. The following is the full file.

import { Injectable, Component } from '@angular/core';
import { CanActivate, Router } from '@angular/router';

import { AuthService } from './auth.service';

@Injectable()
export class AuthGuardService implements CanActivate {

    constructor(private authService: AuthService, private router: Router) {
    }

    canActivate() {
        if (this.authService.loggedIn) {
            return true;
        }
        else {
            this.router.navigate(['unauthorized']);
        }
    }
}

As you can see in the canActivate function if the user is logged in then the function returns true otherwise, the user is routed to the unauthorized component. Before the changes in this post, this dropped the user back on the home page since the unauthorized component didn’t exist.

Wrapping up

With the changes above the user gets a slightly better experience. Just being dropped on the home page wasn’t very helpful as to why that was happening. This at least lets the user know they need to log in. Another option could be to hide the navigation for the routes they don’t have access to until they log it.

The finished version of the code can be found here.


Also published on Medium.

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.