Angular 2 - Routing - CanActivate work with Observable

前端 未结 7 1015
终归单人心
终归单人心 2020-11-30 18:30

I have an AuthGuard (used for routing) that implements CanActivate.

canActivate() {
    return this.loginService.isLoggedIn         


        
相关标签:
7条回答
  • 2020-11-30 18:35

    This may help you

    import { Injectable } from '@angular/core';
    import { CanActivate, Router } from '@angular/router';
    import { Select } from '@ngxs/store';
    import { Observable } from 'rxjs';
    import { map, take } from 'rxjs/operators';
    import { AuthState } from 'src/app/shared/state';
    
    export const ROLE_SUPER = 'ROLE_SUPER';
    
    @Injectable()
    export class AdminGuard implements CanActivate {
    
     @Select(AuthState.userRole)
      private userRoles$: Observable<string[]>;
    
      constructor(private router: Router) {}
    
     /**
       * @description Checks the user role and navigate based on it
       */
    
     canActivate(): Observable<boolean> {
        return this.userRoles$.pipe(
          take(1),
          map(userRole => {
            console.log(userRole);
            if (!userRole) {
              return false;
            }
            if (userRole.indexOf(ROLE_SUPER) > -1) {
              return true;
            } else {
              this.router.navigate(['/login']);
            }
            return false;
          })
        );
      } // canActivate()
    } // class
    
    0 讨论(0)
  • 2020-11-30 18:35

    CanActivate does work with Observable but fails when 2 calls are made like CanActivate:[Guard1, Guard2].
    Here if you return an Observable of false from Guard1 then too it will check in Guard2 and allow access to route if Guard2 returns true. In order to avoid that, Guard1 should return a boolean instead of Observable of boolean.

    0 讨论(0)
  • 2020-11-30 18:44

    You should upgrade "@angular/router" to the latest . e.g."3.0.0-alpha.8"

    modify AuthGuard.ts

    @Injectable()
    export class AuthGuard implements CanActivate {
        constructor(private loginService:LoginService, private router:Router) { }
    
        canActivate(next:ActivatedRouteSnapshot, state:RouterStateSnapshot) {
            return this.loginService.isLoggedIn().map(e => {
                if (e) {
                    return true;
                }
            }).catch(() => {
                this.router.navigate(['/login']);
                return Observable.of(false);
            });
        }   
    }
    

    If you have any questions, ask me!

    0 讨论(0)
  • 2020-11-30 18:46

    I've done it in this way:

    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
    return this.userService.auth(() => this.router.navigate(['/user/sign-in']));}
    

    As you can see I'm sending a fallback function to userService.auth what to do if http call fails.

    And in userService I have:

    import 'rxjs/add/observable/of';
    
    auth(fallback): Observable<boolean> {
    return this.http.get(environment.API_URL + '/user/profile', { withCredentials: true })
      .map(() => true).catch(() => {
        fallback();
        return Observable.of(false);
      });}
    
    0 讨论(0)
  • 2020-11-30 18:51

    Updating Kery Hu's answer for Angular 5+ and RxJS 5.5 where the catch operator is deprecated. You should now use the catchError operator in conjunction with pipe and lettable operators.

    import { Injectable } from '@angular/core';
    import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
    import { Observable } from 'rxjs/Observable';
    import { catchError, map} from 'rxjs/operators';
    import { of } from 'rxjs/observable/of';
    
    @Injectable()
    export class AuthGuard implements CanActivate {
    
      constructor(private loginService: LoginService, private router: Router) { }
    
      canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean>  {
        return this.loginService.isLoggedIn().pipe(
          map(e => {
            if (e) {
              return true;
            } else {
              ...
            }
          }),
          catchError((err) => {
            this.router.navigate(['/login']);
            return of(false);
          })
        );
      }   
      
    }
    
    0 讨论(0)
  • 2020-11-30 18:52

    in canActivate(), you can return a local boolean property (default to false in your case).

    private _canActivate: boolean = false;
    canActivate() {
      return this._canActivate;
    }
    

    And then in the result of the LoginService, you can modify the value of that property.

    //...
    this.loginService.login().subscribe(success => this._canActivate = true);
    
    0 讨论(0)
提交回复
热议问题