【问题标题】:Angular2 auth guard with http request and observablesAngular2 auth 保护与 http 请求和 observables
【发布时间】:2016-12-27 10:55:56
【问题描述】:

我目前正在实现一个以 spring boot 作为后端的 angular2 示例应用程序。我在前端 auth 保护机制和 observables 方面遇到了一些问题。

我正在努力实现:

  1. 当有人进入受保护的路由时,auth guard 应该检查用户是否 已在身份验证服务变量中设置
  2. 如果未设置,则应发出 http 请求以检查会话是否可用
  3. 服务方法应该返回一个真/假值(异步因为可能的 http 请求)
  4. 如果服务返回 false,则身份验证保护应重定向到登录页面
  5. auth guard 应该返回 true/false,这样路由可以被激活也可以不被激活

我的代码目前看起来像这样(顺便说一句,我使用的是 RC5。):

身份验证保护

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

问题是:守卫永远不允许路由器组件激活,即使我已登录。

感谢您的帮助!

【问题讨论】:

  • 有什么问题?
  • 查看编辑,即使我成功登录,路由器组件也永远不会激活。如果我不使用任何可观察对象,它工作正常,但我不能使用 http 请求,所以这不是我的选择。

标签: authentication angular angular2-routing observable angular2-http


【解决方案1】:

改变

return subject.asObservable();

return subject.asObservable().first();

路由器等待 observable 完成。 first() 在第一个事件之后完成。

【讨论】:

  • 感谢这解决了部分问题。现在发生的事情是,当我单击受保护的路线时,它总是会阻止该路线激活并打印日志消息。但是当我在登录屏幕中输入有效的身份验证凭据并且服务器回复 200 OK 时,我仍然无法访问受保护的路由。当我按 f5 并刷新页面时,我突然可以访问受保护的路线。这可能是由于我存储用户对象的服务类中的 authenticatedUser 变量,但我不知道为什么,有什么想法吗?
  • 您可以尝试在isAuthenticated() 中使用BehaviorSubject 而不是Subject。目前,如果 this.authenticatedUsertrue 您发出 true 但此时还没有订阅者。此代码部分同步执行,true 在执行return subject.asObservable() 之前发出,isAuthenticated() 的调用者不会收到此事件。
  • 我不得不结合使用 BehavorSubject(服务)和 ReplaySubject(守卫),但它现在按预期工作。谢谢!
  • 很高兴听到你想通了 :)
  • @Tim 你能分享一些你的工作解决方案的代码示例吗?我遇到了同样的问题,看到一个工作示例会非常有帮助。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-08
  • 1970-01-01
  • 2017-08-10
  • 2017-03-24
  • 2015-11-12
  • 2014-05-02
相关资源
最近更新 更多