Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Async authguard in angular 6

Tags:

I would like to provide a server-side authentication before I give access to a specific route in angular.

I have a AuthGuard which implements CanActivate and a service AuthService. The authService already has a private loggedIn: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(null); which views subscribe to in order to know if the user is logged in or not. I don't really know if my approach is wrong, but it does not seem to work.

This is what I have in auth.guard.ts:

canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot) : Observable<boolean> {
    return this.authService.isAuthenticated().map((isLoggedIn) => {
        if (isLoggedIn) {
            return true;
        } else {
            this.router.navigate(['/login']);
            return false;
        }
    })
}

and this is auth.service.ts:

    @Injectable()
export class AuthService {
    private loggedIn: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(null);

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

    }

    get isLoggedIn() {
        return this.loggedIn.asObservable();
    }

    isAuthenticated() : Observable<boolean> {
        const headers = new HttpHeaders().set("X-Requested-With", "XMLHttpRequest");

        return this.http.get('/user', {headers: headers}).map(
            response => {
                if (response['username']) {
                    this.loggedIn.next(true);
                    return true;
                } else {
                    return false;
                }
            }
        )
    }
like image 502
timber.auhani Avatar asked Jun 05 '18 16:06

timber.auhani


People also ask

How does AuthGuard work in angular?

AuthGuard is used to protect the routes from unauthorized access in angular. How AuthGuard Works? Auth guard provide lifecycle event called canActivate. The canActivate is like a constructor.

How does canActivate work in angular?

The canActivate method returns a boolean indicating whether or not navigation to a route should be allowed. If the user isn't authenticated, they are re-routed to some other place, in this case a route called /login . Now the guard can be applied to any routes you wish to protect.

What is gaurds in angular?

Guards in Angular are nothing but the functionality, logic, and code which are executed before the route is loaded or the ones leaving the route. Different types of guards, CanActivate guard (e.g. it checks route access). CanActivateChild guard (checks child route access).


1 Answers

Here is approach for RXJS6, added a variable _isAuthenticated in authentication service to request the server state just when the flag is disabled. I hope that helps others.

Ensure canActivate returns a plain boolean or an observable. The route handler will subscribe to the given observable and reacts to first boolean value coming from the value stream.

auth.guard.ts

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

import { Observable } from 'rxjs/';
import { map, finalize } from 'rxjs/operators';
import { DataService } from '../data.service';
import { AuthenticationService } from './authentication.service';

@Injectable()
export class AuthenticationGuard implements CanActivate {

  constructor(private router: Router,
              private dataService: DataService,
              private authenticationService: AuthenticationService) { }

  canActivate(): any {
    const isAuthenticated = this.authenticationService.isAuthenticated();

    // All good
    if ( isAuthenticated ) {
      return true;

    // Hmm, let's verify the user first
    } else {
      return this.authenticationService.isSessionAlive()
        .pipe(
          map(res => {

            // No valid session; let's move to the login page
            if ( res === false ) {
              this.router.navigate(['/login'], { replaceUrl: true });
            }

            return res;
          })
        );
    }
  }

}

auth.service.ts (I'm using rxjs 6)

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { DataService } from '@app/core';

@Injectable()
export class AuthenticationService {

  private _isAuthenticated = false;

  constructor(
    private dataService: DataService
  ) {}

  isAuthenticated(): boolean {
    return this._isAuthenticated;
  }

  isSessionAlive(): Observable<any> {
    return Observable.create((observer) => {
      this.dataService.SessionIsAlive()
        .subscribe((res) => {
          this._isAuthenticated = true;
          observer.next(res.success); // your server response
        }, (err) => {
          this._isAuthenticated = false;
          observer.next(false);
          // observer.error(err); // won't work here you need to use next
        });
    });
  }
}
like image 188
Maertz Avatar answered Oct 13 '22 00:10

Maertz