Angular 2-라우팅-Observable로 CanActivate 작업


94

나는이 AuthGuard 가 구현 (라우팅에 사용) CanActivate을 .

canActivate() {
    return this.loginService.isLoggedIn();
}

내 문제는 CanActivate-결과가 HTTP-GET-결과에 달려 있다는합니다 - LoginService를 다시 표시 관찰 가능한 .

isLoggedIn():Observable<boolean> {
    return this.http.get(ApiResources.LOGON).map(response => response.ok);
}

그것들을 어떻게 모을 수 있습니까? CanActivate가 백엔드 상태에 의존하도록 만들 수 있습니까?

# # # # # #

편집 :이 질문은 2016 년의 것입니다. 앵귤러 / 라우터의 매우 초기 단계가 사용되었습니다.

# # # # # #


2
여기 읽어 보셨나요? angular.io/docs/ts/latest/guide/router.html 여기에 경로 경비에 대한 검색 CanActivate에 대한 API 참조입니다 : angular.io/docs/ts/latest/api/router/index/... 당신이 중 하나를 반환 할 수 있습니다 참조로 부울 또는 관찰 가능한 <부울>
mollwe

4
canActivate()를 반환 할 수 있으며이 완료 Observable되었는지 확인하십시오 Observable(예 :) observer.complete().
Philip Bulley

1
@PhilipBulley 관찰 가능 항목이 더 많은 값을 방출 한 다음 완료되면 어떻게 될까요? 경비원은 무엇을합니까? 지금까지 내가 본 것은 take(1)Rx 연산자를 사용 하여 스트림의 전체를 달성하는 것입니다. 추가하는 것을 잊으면 어떻게됩니까?
Felix

답변:


146

"@ angular / router"를 최신. 예 : "3.0.0-alpha.8"

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);
        });
    }   
}

궁금한 점이 있으면 물어보세요!


3
이것은 매우 유사한 방식으로 promise와 함께 작동한다는 점을 지적 할 가치가 있습니다. 내 구현을 위해라고 가정 isLoggedIn()하면 Promise, 할 수 있습니다 isLoggedIn().then((e) => { if (e) { return true; } }).catch(() => { return false; });바라건대 이것은 미래의 여행자에게 도움이됩니다!
kbpontius

6
나는 추가했다import 'rxjs/add/observable/of';
marc_aragones

1
지금은 좋은 대답이 아닙니다. IMO .. 그것은 서버 측에서 일어나는 일에 대한 세부 사항을 제공하지 않습니다 ... 알파에서 구식입니다! ... 그것은 ..이 최선의 방법을 따르지 않는 angular.io/docs/ts/latest/guide/... .. (희망 하나 이상의 일) 아래에있는 내 업데이트 된 대답을 참조
danday74

1
canActivate해야 retun 관찰 가능한 <부울>
아브 Schniederman

큰 도움 :) 감사합니다
gschambial

59

각도 5+ 및 RxJS 5.5 Kery 후의 대답 업데이트 연산자는 사용되지 않습니다를. 이제 pipelettable 연산자 와 함께 catchError 연산자를 사용해야합니다 .catch

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);
      })
    );
  }   
  
}

isLoggedIn () 이후에 XHR 호출이 1 개 더 있고 XHR 결과가 두 번째 XHR 호출에 사용됩니다. 첫 번째 결과를 수락하는 두 번째 ajax 호출을받는 방법은 무엇입니까? 당신이 준 예제는 매우 쉽습니다. 다른 ajax도 가지고 있다면 pipe () 사용법을 알려 주실 수 있습니까?
Pratik 2008-08-08

각도 10에도 매우 유용합니다
Ruslan López

9

canActivate ()Observable<boolean>반환 된 값으로 받아들 입니다. 경비원은 Observable이 해결하고 값을 볼 때까지 기다릴 것입니다. 'true'이면 검사를 통과하고, 그렇지 않으면 (다른 데이터 또는 throw 된 오류) 경로를 거부합니다.

당신은 사용할 수 있습니다 .map를 변환 연산자 Observable<Response>Observable<boolean>이렇게 같은 :

canActivate(){
    return this.http.login().map((res: Response)=>{
       if ( res.status === 200 ) return true;
       return false;
    });
}

1
캐치 블록은 어떻습니까? catch 블록이 401이면 호출됩니다.
danday74

1
각도 4에서는 작동하지 않습니다. 제네릭 유형을 정의 할 곳이 필요합니다.
gtzinos

2

나는 이런 식으로 그것을했다 :

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

보시다시피 http 호출이 실패하면 어떻게 해야할지 userService.auth에 폴백 함수를 보냅니다.

그리고 userService에는 다음이 있습니다.

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);
  });}

.map () 함수 측면에서 정말 좋은 답변-정말 좋아요 :)-폴백 콜백을 사용하지 않았습니다-대신 canActivate 메소드에서 auth Observable을 구독했습니다-아이디어에 감사드립니다
danday74

0

이것은 당신을 도울 수 있습니다

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

-1

CanActivate는 Observable과 함께 작동하지만 CanActivate : [Guard1, Guard2]와 같이 2 번 호출하면 실패합니다.
여기에서 Guard1에서 False의 Observable을 반환하면 Guard2도 체크인하고 Guard2가 true를 반환하면 경로에 대한 액세스를 허용합니다. 이를 피하기 위해 Guard1은 Observable 대신 boolean을 반환해야합니다.


-10

canActivate ()에서 로컬 부울 속성 (귀하의 경우 기본값은 false)을 반환 할 수 있습니다.

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

그런 다음 LoginService의 결과에서 해당 속성의 값을 수정할 수 있습니다.

//...
this.loginService.login().subscribe(success => this._canActivate = true);

당신은 천재입니다.
Kien Nguyen Ngoc
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.