Adding AuthResponseInterceptor

We're almost done; the last thing we need to do is to provide our client with a HttpInterceptor that will capture the Http 401 - Unauthorized errors and try to refresh the access token accordingly. It goes without saying that we need to find a way to have it trigger only once--to avoid endless attempts--and to resend the failed request in case of success.

From Solution Explorer, right-click to the /ClientApp/app/services/ folder and add a new auth.response.interceptor.ts TypeScript file, filling it with the following content:

import { Injectable, Injector } from "@angular/core";
import { Router } from "@angular/router";
import {
HttpClient,
HttpHandler, HttpEvent, HttpInterceptor,
HttpRequest, HttpResponse, HttpErrorResponse
} from "@angular/common/http";
import { AuthService } from "./auth.service";
import { Observable } from "rxjs";

@Injectable()
export class AuthResponseInterceptor implements HttpInterceptor {

currentRequest: HttpRequest<any>;
auth: AuthService;

constructor(
private injector: Injector,
private router: Router
)
{ }

intercept(
request: HttpRequest<any>,
next: HttpHandler): Observable<HttpEvent<any>> {

this.auth = this.injector.get(AuthService);
var token = (this.auth.isLoggedIn()) ?
this.auth.getAuth()!.token : null;

if (token) {
// save current request
this.currentRequest = request;

return next.handle(request)
.do((event: HttpEvent<any>) => {
if (event instanceof HttpResponse) {
// do nothing
}
})
.catch(error => {
return this.handleError(error)
});
}
else {
return next.handle(request);
}
}

handleError(err: any) {
if (err instanceof HttpErrorResponse) {
if (err.status === 401) {
// JWT token might be expired:
// try to get a new one using refresh token
console.log("Token expired. Attempting refresh...");
this.auth.refreshToken()
.subscribe(res => {
if (res) {
// refresh token successful
console.log("refresh token successful");

// re-submit the failed request
var http = this.injector.get(HttpClient);
http.request(this.currentRequest).subscribe(
result => {
// do something
}, error => console.error(error)
);
}
else {
// refresh token failed
console.log("refresh token failed");

// erase current token
this.auth.logout();

// redirect to login page
this.router.navigate(["login"]);
}
}, error => console.log(error));
}
}
return Observable.throw(err);
}
}

That's an impressive amount of TypeScript code, but the included comments should help us properly understand what we did:

  • In the intercept() method, the first thing we do is check whether there's a token or not; if we don't, there's no need to do anything, otherwise we do two things:
    • Store a reference to the current request in an internal property that can be useful later on
    • Set up an event handler that will call the handleError() method in case of HTTP errors
  • In the handleError() method, we check whether we're dealing with an HttpErrorResponse with a status code of 401 - Unauthorized, which is what we get whenever we attempt to access a controller's action method shielded with the [Authorize] attribute using an invalid (expired) access token. If the conditions match, we attempt to refresh the token using the refreshToken() method of AuthService we implemented a short while ago and subscribe to it, waiting for the outcome:
    • In case of success, we resubmit the request that triggered the response error--which we stored in the this.currentRequest local property
    • In case of failure, we perform the logout to clear all the expired tokens from the local storage and then redirect the user back to the login screen
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.147.77