amigoscode / full-stack-professional

https://amigoscode.com/courses/full-stack-professional
432 stars 205 forks source link

Implement the Access Guard and Secure the Customers Route #18

Open hazartilirot opened 1 year ago

hazartilirot commented 1 year ago

Here would be a tricky one.

Open your guard directory in a terminal window, and enter the following: ng generate guard Access

In the app.module.ts file, in the bottom, paste the code:

export class AppModule {
    constructor(private injector: Injector) {
        AppInjector = this.injector;
    }
}

Right after all imports and before @Ngmodule paste the piece: export let AppInjector: Injector;

you would also need to import Injector import { Injector, NgModule } from "@angular/core";

I leave my complete authentication.service.ts,

import { Inject, Injectable, Injector } from "@angular/core";

import { AuthenticationRequest } from "../../models/authentication-request";
import { AuthenticationResponse } from "../../models/authentication-response";
import { Observable } from "rxjs";
import { HttpClient } from "@angular/common/http";
import { JwtHelperService } from "@auth0/angular-jwt";
import { Router } from "@angular/router";

@Injectable({
    providedIn: "root"
})
export class AuthenticationService {

    constructor(
        private http: HttpClient,
        private router: Router,
    ) {
    }

    authenticate(credentialsForLogin: AuthenticationRequest): Observable<AuthenticationResponse> {
        return this.http.post<AuthenticationResponse>(
            "http://localhost:8080/api/v1/auth/login",
            credentialsForLogin
        );
    }

    setSession(authenticationResponse: AuthenticationResponse): void {
        localStorage.setItem("userId", `${authenticationResponse.customerDto.id}`);
        localStorage.setItem("token", authenticationResponse.token);
    }

    isSessionValid(): boolean {
        const userId: number = Number(localStorage.getItem("userId"));
        const token: string = localStorage.getItem("token");

        if (this.isLocalStorageInfringed(userId, token) || this.isTokenExpired(token)) {
            this.logout();
            return false;
        }
        return true;
    }

    private logout(): void {
        localStorage.clear();
        this.router.navigate(["login"])
    }

    private isTokenExpired(token: string): boolean {
        return new JwtHelperService().isTokenExpired(token);
    }

    private isLocalStorageInfringed(userId: number, token: string): boolean {
        return !userId || !token;
    }
}

in login.component.ts insert in constructor

if (authenticationService.isSessionValid()) {
            router.navigate(["customer"]);
        }

the login function in the same file has setSeesion method you need to place

next: authenticationResponse => {
                    this.authenticationService.setSession(authenticationResponse);
                    this.router.navigate(["customer"]);
                },

Now the Guard itself.... I just don't know how to create an instance in the method... It complains on httpClient, then router.... so I've found a solution relying on injection

import { CanActivateFn } from "@angular/router";
import { AuthenticationService } from "../authentication/authentication.service";
import { AppInjector } from "../../app.module";

export const accessGuard: CanActivateFn = (route, state) => {
    return AppInjector.get(AuthenticationService).isSessionValid()
};