attilan

Auth service

Oct 19th, 2021
667
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import { BehaviorSubject, Observable, of } from 'rxjs';
  2. import { Injectable, Injector } from '@angular/core';
  3. import { Router } from '@angular/router';
  4. import { AppConfig } from '@config/app.config';
  5. import { AUTH_STORAGE } from '@shared/modules/auth/providers/auth-storage.injection-token';
  6. import { IAuthStorageStrategy } from '@shared/modules/auth/classes/IAuthStorageStrategy';
  7. import { JwtHelperService } from '@auth0/angular-jwt';
  8. import { JwtToken } from '@shared/classes/jwtToken';
  9. import { EndpointsConfig } from '@config/endpoints.config';
  10. import { AuthRequestDto } from '@shared/modules/auth/classes/AuthRequestDto';
  11. import { catchError, concatMap, tap } from 'rxjs/operators';
  12. import { ToastService } from '@shared/modules/toast/services/toast.service';
  13. import { SetFirstPasswordDto } from '@shared/modules/auth/classes/SetFirstPasswordDto';
  14. import { getGeneralMessage } from '@shared/utils/generate-general-toast-message.util';
  15. import { Location } from '@angular/common';
  16. import { UserService } from '@pages/users/services/user.service';
  17. import { includes } from 'lodash-es';
  18. import { HttpErrorResponse } from '@angular/common/http';
  19. import { HttpService } from '../../http/http.service';
  20. import { User } from '../classes/User';
  21. import { UserRole } from '../classes/UserRole';
  22. import { AuthGuardParams } from '../classes/AuthGuardParams';
  23.  
  24. /** Write/read data of user's to/from local storage, */
  25. @Injectable({
  26.   providedIn: 'root',
  27. })
  28. export class AuthService {
  29.   loggedInUser: User;
  30.   loggedInUserChange: BehaviorSubject<User> = new BehaviorSubject<User>(null);
  31.   previousURL: string;
  32.  
  33.   readonly authStorage: IAuthStorageStrategy;
  34.   private readonly jwtHelper: JwtHelperService;
  35.   private readonly router: Router;
  36.  
  37.   constructor(private httpService: HttpService, private injector: Injector) {
  38.     this.authStorage = injector.get<IAuthStorageStrategy>(AUTH_STORAGE);
  39.     this.jwtHelper = injector.get<JwtHelperService>(JwtHelperService);
  40.     this.router = injector.get<Router>(Router);
  41.   }
  42.  
  43.   get isSuperAdmin(): boolean {
  44.     return includes(this.getUserRoles(), UserRole.SuperAdmin);
  45.   }
  46.  
  47.   setUserAndToken(token, userData) {
  48.     this.setUser(userData);
  49.   }
  50.  
  51.   redirectToPreviousUrlOrHome() {
  52.     if (this.previousURL) {
  53.       const splitUrl = this.previousURL.split('?');
  54.       const route = splitUrl[0];
  55.       const { queryParams } = this.router.parseUrl(this.previousURL);
  56.       this.router.navigate([route], { queryParams });
  57.       this.previousURL = null;
  58.     } else {
  59.       this.router.navigate([AppConfig.homeUrl]);
  60.     }
  61.   }
  62.  
  63.   logout(doRedirect?: boolean) {
  64.     const router = this.injector.get<Router>(Router);
  65.  
  66.     this.authStorage.removeAll();
  67.     sessionStorage.clear();
  68.  
  69.     if (this.loggedInUser) {
  70.       this.setUser(null);
  71.     }
  72.  
  73.     if (doRedirect) {
  74.       router.navigate([AppConfig.loginUrl]);
  75.     }
  76.   }
  77.  
  78.   login(payload: AuthRequestDto): Observable<User> {
  79.     return this.httpService.post(EndpointsConfig.login, payload).pipe(
  80.       concatMap(() => this.loadUser()),
  81.       tap((user: User) => {
  82.         this.setUser(user);
  83.         this.redirectToPreviousUrlOrHome();
  84.       })
  85.     );
  86.   }
  87.  
  88.   logoutWithApi() {
  89.     return this.httpService.post(EndpointsConfig.logout, null).pipe(tap(() => this.logout(true)));
  90.   }
  91.  
  92.   resetPassword(
  93.     payload: SetFirstPasswordDto | { email: string },
  94.     isSetFirstPasswordMode: boolean
  95.   ): Observable<unknown> {
  96.     const toastService = this.injector.get<ToastService>(ToastService);
  97.  
  98.     const endpoint = isSetFirstPasswordMode
  99.       ? EndpointsConfig.resetPassword
  100.       : EndpointsConfig.forgotPassword;
  101.  
  102.     const message = isSetFirstPasswordMode
  103.       ? 'auth_forms.reset_password_request'
  104.       : 'auth_forms.send_email';
  105.  
  106.     return this.httpService.post(endpoint, payload).pipe(
  107.       tap(() => {
  108.         toastService.showSuccess(getGeneralMessage(message, true));
  109.         this.router.navigate([AppConfig.loginUrl]);
  110.       }),
  111.       catchError((err) => {
  112.         toastService.showError(getGeneralMessage(`${message}_detailed`, false));
  113.         return of(err);
  114.       })
  115.     );
  116.   }
  117.  
  118.   loadUser(): Observable<User | HttpErrorResponse> {
  119.     const userService = this.injector.get<UserService>(UserService);
  120.     const toastService = this.injector.get<ToastService>(ToastService);
  121.  
  122.     return this.httpService.get(EndpointsConfig.me).pipe(
  123.       tap((me: User) => {
  124.         userService.setState({ me });
  125.       }),
  126.       catchError((err) => {
  127.         toastService.showError('auth_forms.load_user_error');
  128.         this.logout(true);
  129.         return of(err);
  130.       })
  131.     );
  132.   }
  133.  
  134.   checkAuth(): Promise<boolean> {
  135.     console.log('check auth-user!');
  136.  
  137.     const csrfToken = this.authStorage.readCSRFToken();
  138.  
  139.     if (!csrfToken) {
  140.       return Promise.resolve(true);
  141.     }
  142.  
  143.     return new Promise((resolve) => {
  144.       this.loadUser().subscribe(
  145.         (userData: User | HttpErrorResponse) => {
  146.           if (userData instanceof HttpErrorResponse) {
  147.             resolve(true);
  148.             throw new Error(`Login error occurred: ${userData.message}`);
  149.           }
  150.  
  151.           const location = this.injector.get(Location);
  152.           this.setUser(userData);
  153.           if (location.path().includes(AppConfig.loginUrl)) {
  154.             this.redirectToPreviousUrlOrHome();
  155.           }
  156.           resolve(true);
  157.         },
  158.         () => {
  159.           this.logout();
  160.           resolve(true);
  161.         }
  162.       );
  163.     });
  164.   }
  165.  
  166.   redirectToHomeByRole(authGuardParams: AuthGuardParams, previousUrl: string) {
  167.     let route;
  168.     const userRoles = this.getUserRoles();
  169.  
  170.     if (authGuardParams.redirectTo) {
  171.       route = authGuardParams.redirectTo;
  172.     } else if (userRoles?.length > 0 && userRoles[0] !== UserRole.UnAuthorized) {
  173.       const roleRouteMap = {
  174.         [UserRole.SuperAdmin]: AppConfig.homeUrl,
  175.         [UserRole.Admin]: AppConfig.homeUrl,
  176.         [UserRole.FieldManager]: AppConfig.homeUrl,
  177.         [UserRole.ProjectManager]: AppConfig.homeUrl,
  178.         [UserRole.Partner]: AppConfig.positionsUrl,
  179.         [UserRole.Candidate]: AppConfig.positionsUrl,
  180.       };
  181.       route = roleRouteMap[userRoles[0]];
  182.     } else {
  183.       route = AppConfig.loginUrl;
  184.     }
  185.  
  186.     this.previousURL = previousUrl;
  187.     this.router.navigate([route]);
  188.   }
  189.  
  190.   private checkJWTAuthToken(token): JwtToken | null {
  191.     const jwtToken = this.getDecodedToken(token);
  192.     if (!jwtToken || !jwtToken.sub || !jwtToken.exp) {
  193.       return null;
  194.     }
  195.     if (this.jwtHelper.isTokenExpired(token, 60 * 30)) {
  196.       console.log('TODO: JWT TOKEN EXPIRED');
  197.       return null;
  198.     }
  199.  
  200.     return jwtToken;
  201.   }
  202.  
  203.   private getDecodedToken(token: string): JwtToken {
  204.     try {
  205.       return this.jwtHelper.decodeToken(token);
  206.     } catch (error) {
  207.       console.log('error while parsing token: ', error);
  208.       return null;
  209.     }
  210.   }
  211.  
  212.   private setUser(userData: User | null) {
  213.     if (userData) {
  214.       this.loggedInUser = userData;
  215.     } else {
  216.       this.loggedInUser = null;
  217.     }
  218.     this.loggedInUserChange.next(this.loggedInUser);
  219.   }
  220.  
  221.   getLoggedInUser(): User {
  222.     return this.loggedInUser;
  223.   }
  224.  
  225.   isLoggedIn(): boolean {
  226.     return !!this.loggedInUser;
  227.   }
  228.  
  229.   getAuthToken(): string {
  230.     const authToken = this.authStorage.readAuthToken();
  231.     if (this.checkJWTAuthToken(authToken)) {
  232.       return authToken;
  233.     }
  234.  
  235.     return null;
  236.   }
  237.  
  238.   getUserRoles(): UserRole[] {
  239.     let roles = [UserRole.UnAuthorized];
  240.  
  241.     if (Array.isArray(this.loggedInUser?.roles)) {
  242.       roles = this.loggedInUser?.roles.map((userRole) => userRole.name);
  243.     }
  244.  
  245.     return roles;
  246.   }
  247. }
  248.  
RAW Paste Data