From 9fea964cf7674eefdee5ee6deb4ce25cc7407d7e Mon Sep 17 00:00:00 2001 From: Igor Propisnov Date: Thu, 18 Jul 2024 21:05:28 +0200 Subject: [PATCH] Added authguard for protected routes --- frontend/src/app/app.routes.ts | 3 + frontend/src/app/shared/guards/auth.guard.ts | 22 +++++++ frontend/src/app/shared/guards/index.ts | 1 + .../src/app/shared/service/auth.service.ts | 58 +++++++++++++------ 4 files changed, 67 insertions(+), 17 deletions(-) create mode 100644 frontend/src/app/shared/guards/auth.guard.ts create mode 100644 frontend/src/app/shared/guards/index.ts diff --git a/frontend/src/app/app.routes.ts b/frontend/src/app/app.routes.ts index 248a466..1459b8f 100644 --- a/frontend/src/app/app.routes.ts +++ b/frontend/src/app/app.routes.ts @@ -1,5 +1,7 @@ import { Routes } from '@angular/router'; +import { AuthGuard } from './shared/guards'; + const simpleLayoutRoutes: Routes = [ { path: '', @@ -43,6 +45,7 @@ export const routes: Routes = [ import('./layout/main-layout/layout.component').then( (m) => m.LayoutComponent ), + canActivate: [AuthGuard], children: [ { path: '', diff --git a/frontend/src/app/shared/guards/auth.guard.ts b/frontend/src/app/shared/guards/auth.guard.ts new file mode 100644 index 0000000..44ba7f6 --- /dev/null +++ b/frontend/src/app/shared/guards/auth.guard.ts @@ -0,0 +1,22 @@ +import { inject } from '@angular/core'; +import { Router, CanActivateFn } from '@angular/router'; + +import { map, take } from 'rxjs'; + +import { AuthService } from '../service'; + +export const AuthGuard: CanActivateFn = () => { + const authService: AuthService = inject(AuthService); + const router: Router = inject(Router); + + return authService.status().pipe( + take(1), + map((response) => { + if (response.success) { + return true; + } else { + return router.createUrlTree(['/welcome']); + } + }) + ); +}; diff --git a/frontend/src/app/shared/guards/index.ts b/frontend/src/app/shared/guards/index.ts new file mode 100644 index 0000000..b41e34a --- /dev/null +++ b/frontend/src/app/shared/guards/index.ts @@ -0,0 +1 @@ +export * from './auth.guard'; diff --git a/frontend/src/app/shared/service/auth.service.ts b/frontend/src/app/shared/service/auth.service.ts index 2f9b247..36a4e9e 100644 --- a/frontend/src/app/shared/service/auth.service.ts +++ b/frontend/src/app/shared/service/auth.service.ts @@ -1,45 +1,69 @@ -import { Injectable } from '@angular/core'; +import { Injectable, WritableSignal, signal } from '@angular/core'; +import { toObservable } from '@angular/core/rxjs-interop'; -import { BehaviorSubject, Observable } from 'rxjs'; +import { Observable, of, throwError } from 'rxjs'; +import { catchError, shareReplay, tap } from 'rxjs/operators'; import { + AuthenticationApiService, SigninResponseDtoApiModel, + SuccessDtoApiModel, UserCredentialsDtoApiModel, } from '../../api'; -import { AuthenticationApiService } from '../../api/api/authentication.api.service'; - -type SuccessResponse = { - success: boolean; -}; @Injectable({ providedIn: 'root', }) export class AuthService { - public isAuthenticated$: BehaviorSubject = - new BehaviorSubject(false); + public isAuthenticatedSignal: WritableSignal = signal(false); + public isAuthenticated$: Observable = toObservable( + this.isAuthenticatedSignal + ); + private statusCheck$: Observable; public constructor( private readonly authenticationApiService: AuthenticationApiService - ) {} + ) { + this.statusCheck$ = this.initializeStatusCheck(); + } public signup( credentials: UserCredentialsDtoApiModel - ): Observable { - return this.authenticationApiService.authControllerSignup(credentials); + ): Observable { + return this.authenticationApiService + .authControllerSignup(credentials) + .pipe(tap(() => this.isAuthenticatedSignal.set(true))); } public signin( credentials: UserCredentialsDtoApiModel ): Observable { - return this.authenticationApiService.authControllerSignin(credentials); + return this.authenticationApiService + .authControllerSignin(credentials) + .pipe(tap(() => this.isAuthenticatedSignal.set(true))); } - public signout(): Observable { - return this.authenticationApiService.authControllerSignout(); + public signout(): Observable { + return this.authenticationApiService + .authControllerSignout() + .pipe(tap(() => this.isAuthenticatedSignal.set(false))); } - public status(): Observable { - return this.authenticationApiService.authControllerStatus(); + public status(): Observable { + if (this.isAuthenticatedSignal()) { + return of({ success: true }); + } + return this.statusCheck$; + } + + private initializeStatusCheck(): Observable { + return this.authenticationApiService.authControllerStatus().pipe( + tap((response) => this.isAuthenticatedSignal.set(response.success)), + catchError((error) => { + this.isAuthenticatedSignal.set(false); + return throwError(() => error); + }), + shareReplay(1) + ); } } -- 2.40.1