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