5

我目前正在實施一個angular2示例應用程序與春季引導作爲後端。我在前端身份驗證機制和可觀察性方面遇到了一些問題。Angular2 auth警衛與http請求和observables

我想實現:

  1. 當有人進入保護路由AUTH後衛應該檢查如果用戶 在身份驗證服務變量
  2. 如果沒有設置則已經設置了HTTP請求應發出以檢查會話是否可用
  3. 服務方法應返回true/false值(由於可能的http請求而異步)
  4. 如果服務返回false,則認證守護應重定向到登錄頁面
  5. 權威性後衛應該返回true/false,這樣的路線可以被激活或不

我的代碼目前看起來是這樣的(我使用RC5 BTW):

驗證衛隊

import {Injectable} from "@angular/core"; 
import {CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router} from "@angular/router"; 
import {Observable, Subject} from "rxjs/Rx"; 
import {AuthService} from "./auth.service"; 

@Injectable() 
export class AuthGuard implements CanActivate { 
    constructor(private authService: AuthService, private router: Router) {} 

    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | boolean { 
    var authenticated = this.authService.isAuthenticated(); 
    var subject = new Subject<boolean>(); 
    authenticated.subscribe(
     (res) => { 
      console.log("onNext guard: "+res); 
      if(!res && state.url !== '/signin') { 
      console.log("redirecting to signin") 
      this.router.navigate(['/signin']); 
      } 
      subject.next(res); 
     }); 
    return subject.asObservable(); 
    } 
} 

驗證服務

import {Injectable} from "@angular/core"; 
import {User} from "./user.interface"; 
import {Router} from "@angular/router"; 
import {Http, Response, Headers} from "@angular/http"; 
import {environment} from "../environments/environment"; 
import {Observable, Observer, Subject} from "rxjs/Rx"; 

@Injectable() 
export class AuthService { 
    private authenticatedUser : User; 
    constructor(private router: Router, private http: Http) {} 

    signupUser(user: User) { 
    } 


    logout() { 
    //do logout stuff 
    this.router.navigate(['/signin']); 
    } 

    isAuthenticated() : Observable<boolean> { 
    var subject = new Subject<boolean>(); 
    if (this.authenticatedUser) { 
     subject.next(true); 
    } else { 
     this.http.get(environment.baseUrl + '/user') 
     .map((res : Response) => res.json()) 
     .subscribe(res => { 
      console.log("next: returning true"); 
      this.authenticatedUser = User.ofJson(res); 
      subject.next(true); 
     }, (res) => { 
      console.log("next: returning false"); 
      subject.next(false); 
     }); 
    } 
    return subject.asObservable(); 
    } 
} 

的問題是:警衛從不允許路由器組件激活,即使當我登錄時。

感謝您的幫助!

+0

什麼問題? –

+0

請參閱編輯,即使我成功登錄,路由器組件也不會激活。如果我沒有使用任何可觀察對象,它可以正常工作,但我無法使用http請求,因此對我來說這不是一個選項。 – Tim

回答

7

變化

return subject.asObservable(); 

return subject.asObservable().first(); 

路由器等待觀察的完成。 first()在第一個事件後完成。

+0

謝謝你解決了這個問題的一部分。現在發生的事情是,當我點擊受保護的路由時,它總是阻止路由激活並打印日誌消息。但是當我在登錄屏幕上輸入有效的身份驗證憑據並且服務器回覆200 OK時,我仍然無法訪問受保護的路由。當我按F5並刷新頁面時,我突然可以訪問受保護的路線。這可能是由於存儲用戶對象的服務類中的authenticatedUser變量所致,但我不確定爲什麼,有什麼想法? – Tim

+1

您可以嘗試在'isAuthenticated()'中使用'BehaviorSubject'而不是'Subject'。目前,如果'this.authenticatedUser'爲'true',那麼你發出'true',但此時還沒有用戶。該代碼部分被執行sync並且在執行'return subject.asObservable()'之前發射'true',並且'isAuthenticated()'的調用者不會收到該事件。 –

+2

我不得不使用BehavorSubject(Service)和ReplaySubject(guard)的組合,但它現在按預期工作。謝謝! – Tim