【问题标题】:Async authguard in angular 6角度 6 中的异步 authguard
【发布时间】:2018-07-16 22:15:16
【问题描述】:

在我授予对特定路由的 Angular 访问权限之前,我想提供服务器端身份验证。

我有一个实现 CanActivate 的 AuthGuard 和一个服务 AuthService。 authService 已经有一个 private loggedIn: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(null); 视图订阅,以便了解用户是否登录。我真的不知道我的方法是否错误,但它似乎不起作用。

这就是我在 auth.guard.ts 中的内容:

canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot) : Observable<boolean> {
    return this.authService.isAuthenticated().map((isLoggedIn) => {
        if (isLoggedIn) {
            return true;
        } else {
            this.router.navigate(['/login']);
            return false;
        }
    })
}

这是 auth.service.ts:

    @Injectable()
export class AuthService {
    private loggedIn: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(null);

    constructor(
        private router: Router,
        private http: HttpClient
    ) {

    }

    get isLoggedIn() {
        return this.loggedIn.asObservable();
    }

    isAuthenticated() : Observable<boolean> {
        const headers = new HttpHeaders().set("X-Requested-With", "XMLHttpRequest");

        return this.http.get('/user', {headers: headers}).map(
            response => {
                if (response['username']) {
                    this.loggedIn.next(true);
                    return true;
                } else {
                    return false;
                }
            }
        )
    }

【问题讨论】:

  • 错误是什么?有什么反馈吗?
  • 好吧,此时错误只是一个 401,我想我可以处理,但我觉得我已经尝试了很多事情但没有成功,我只想知道我是否在正确的轨道上......我什至应该让 canActivate 返回一个 Observable 还是一个布尔值? isAuthenticated 也应该提供 Observable 吗?登录变量呢,它是必需的吗?我需要isLoggedIn isAuthenticated,不一样吗?等等...我有点迷茫,真的,我找到了一些代码 sn-ps 但无法让它们工作...

标签: angular angular6


【解决方案1】:

这是 RXJS6 的方法,在身份验证服务中添加了一个变量_isAuthenticated,以在标志被禁用时请求服务器状态。我希望这对其他人有所帮助。

确保canActivate 返回一个普通的布尔值或可观察值。路由处理程序将订阅给定的 observable,并对来自值流的第一个布尔值做出反应。

auth.guard.ts

import { Injectable } from '@angular/core';
import { Router, CanActivate } from '@angular/router';

import { Observable } from 'rxjs/';
import { map, finalize } from 'rxjs/operators';
import { DataService } from '../data.service';
import { AuthenticationService } from './authentication.service';

@Injectable()
export class AuthenticationGuard implements CanActivate {

  constructor(private router: Router,
              private dataService: DataService,
              private authenticationService: AuthenticationService) { }

  canActivate(): any {
    const isAuthenticated = this.authenticationService.isAuthenticated();

    // All good
    if ( isAuthenticated ) {
      return true;

    // Hmm, let's verify the user first
    } else {
      return this.authenticationService.isSessionAlive()
        .pipe(
          map(res => {

            // No valid session; let's move to the login page
            if ( res === false ) {
              this.router.navigate(['/login'], { replaceUrl: true });
            }

            return res;
          })
        );
    }
  }

}

auth.service.ts(我使用的是 rxjs 6)

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { DataService } from '@app/core';

@Injectable()
export class AuthenticationService {

  private _isAuthenticated = false;

  constructor(
    private dataService: DataService
  ) {}

  isAuthenticated(): boolean {
    return this._isAuthenticated;
  }

  isSessionAlive(): Observable<any> {
    return Observable.create((observer) => {
      this.dataService.SessionIsAlive()
        .subscribe((res) => {
          this._isAuthenticated = true;
          observer.next(res.success); // your server response
        }, (err) => {
          this._isAuthenticated = false;
          observer.next(false);
          // observer.error(err); // won't work here you need to use next
        });
    });
  }
}

【讨论】:

  • 这不起作用,因为 _isAuthenticated 布尔值在对服务器的请求完成并能够更改之前,总是在身份验证保护中返回 false。
【解决方案2】:

你可以做一些如下的改变,

您的服务,

@Injectable()
export class LoginService {
  public isUserLoggedIn: boolean;
  constructor(
    private router: Router,
    private auth: AuthService) {
    this.isUserLoggedIn = false;
  }

  public loginService(data): void {
    this.auth.isAuthentication(data)
    .subscribe((response) => {
      if (response) {
        this.isUserLoggedIn = true;             
      }else {
        this.router.navigate(['login']);
      }
    });
  }

 public getUserLoggedIn() {
   return this.isUserLoggedIn;
}

然后,

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(private login: LoginService) { }
  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    return this.login.getUserLoggedIn();
  }
}

【讨论】:

  • 在其他组件上,我曾经有 this.isLoggedIn$ = this.authService.isLoggedIn;然后 *ngIf="isLoggedIn$ | async"。现在相当于什么?
  • this.auth.isAuthentication 是什么?
  • 这是您通过在服务端传递凭据进行身份验证的地方
  • 所以你的意思是我应该把我的 http.get 放在那里,而不是你的 this.auth.isAuthentication(data),对吧?什么是 loginService(data) ?它看起来像第二个构造函数,谁调用它?我试过你的版本,在 chrome 开发工具中,似乎从未调用过 '/user'...
  • 另外,如果我不在loggedIn变量中使用异步,并且记录器断开连接,我的html组件将不会被通知并且ngIf不会改变,不是吗?当用户登录状态发生变化时,我需要在应用程序的各个部分得到通知
猜你喜欢
  • 2019-06-28
  • 2019-04-10
  • 2015-07-06
  • 2019-09-09
  • 2021-04-23
  • 2023-02-01
  • 2020-08-23
  • 2018-07-08
  • 1970-01-01
相关资源
最近更新 更多