Angular 8获取BehaviorSubject的值将返回null [英] Angular 8 getting the value of a BehaviorSubject returns null

查看:104
本文介绍了Angular 8获取BehaviorSubject的值将返回null的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试设置此身份验证解决方案:

I am trying to setup this authentication solution:

https://jasonwatmore.com/post/2019/06/26/angular-8-basic-http-authentication-tutorial-example

AuthenticationService 中,构造函数执行以下操作:

In the AuthenticationService the constructor does this:

constructor(private http: HttpClient) {
    this.currentUserSubject = new BehaviorSubject<Token>(JSON.parse(localStorage.getItem('currentUser')));
    this.currentUser = this.currentUserSubject.asObservable();
}

这似乎很好.实际登录时,使用 next 方法调用 currentUserSubject ,如下所示:

which seems to be fine. When actually logging in, the currentUserSubject is invoked with the next method like this:

this.currentUserSubject.next(user);

问题是,我的 AuthGuard 调用了 currentUserValue 方法,除非刷新页面,否则该方法返回null.

The problem is, my AuthGuard invokes the method currentUserValue which is returning null unless I refresh my page.

该方法非常简单,并且可以执行以下操作:

That method is very simple and does this:

public get currentUserValue(): Token {
    return this.currentUserSubject.value;
}

有人知道为什么会这样吗?我的代码与代码相同在上面的教程中,但由于某种原因,我的系统无法正常工作.

Does anyone know why this is happening? My code is the same as the code on the tutorial above but for some reason mine is not working.

在@LppEdd回答之后,我试图将我的 canActivate 方法更改为:

Following @LppEdd answer, I tried to change my canActivate method to this:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> {
    return this.authenticationService.currentUserSubject.pipe(
       map(user => {
           console.log(user);
           let m = !!user;
           console.log(m);
           return m;
       }),
       catchError(() => of(this.router.createUrlTree(['login'], { queryParams: { retUrl: route.url} }))),
       take(1)
    );
}

当我登录并调用 canActivate 时,第一个 console.log 为null,据我所知不应为null.我的身份验证类现在如下所示:

When I log in and the canActivate is invoked, the first console.log is null and from my understanding it should not be. My authentication class now looks like this:

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import { map } from 'rxjs/operators';
import { Observable, BehaviorSubject } from 'rxjs';

import { environment } from 'src/environments/environment';
import { Token } from './models/token';

@Injectable({
    providedIn: 'root'
})
export class AuthenticationService {
    currentUserSubject: BehaviorSubject<Token>;

    constructor(private http: HttpClient) {
        this.currentUserSubject = new BehaviorSubject<Token>(JSON.parse(localStorage.getItem('currentUser')));
    }

    login(username: string, password: string): Observable<void> {
        const params = new HttpParams({
            fromObject: {
                username,
                password,
                grant_type: 'password',
                scope: 'Sxp'
            }
        });

        const httpOptions = {
            headers: new HttpHeaders({
                'Content-Type': 'application/x-www-form-urlencoded',
                'Authorization': environment.authorization
            })
        };

        return this.http.post<Token>(`${environment.identityServerUrl}/connect/token`, params, httpOptions)
            .pipe(map(user => {
                localStorage.setItem('currentUser', JSON.stringify(user));
                console.log(user);
                this.currentUserSubject.next(user);
            }));
    }

    logout(): void {
        // remove user from local storage to log user out
        localStorage.removeItem('currentUser');
        this.currentUserSubject = undefined;
    }
}


情节变厚.我决定从本教程下载源文件,然后删除伪造的后端提供程序,并用我的真实api替换,包括身份验证,并且它没有任何问题.所以我的项目有问题.


The plot thickens. I decided to download the source files from the tutorial and then remove the fake backend provider and replace with my real api, including the authentication and it worked with no issues. So there is something wrong with my project.

由于我的项目是新项目,所以我只能假定这与延迟加载的路由有关.我将做更多调查,看看是否可以解决.

As my project is new, I can only assume it's something to do with the lazy loaded routes. I am going to do some more investigation to see if I can fix it.

嗯,我不知道.我从教程中获取了文件,然后慢慢地构建了我的应用程序.现在,我将其恢复为原来的样子,并且仍然可以正常工作.....我将接受给出的答案,因为那是我正在使用的并且确实有效

Well, I have no idea. I took the files from the tutorial and slowly built back my application. I have now got it back to the way it was and it all still works..... I am going to accept the answer given to me, because that is what I am using and it does work

推荐答案

CanActivate#canActivate 方法的返回类型指定为

The CanActivate#canActivate method has a return type specified as

Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree

这意味着您实际上可以利用Angular的异步特性(使用RxJS),从而返回 currentUserSubject Observable ,例如

That means you can actually leverage the asynchronous nature of Angular (with RxJS), and thus return your currentUserSubject Observable, e.g.

canActivate(...): Observable<boolean> {
   return this.currentUserSubject.pipe(
      filter(user => !!user), 
      mapTo(true),
      take(1)
   );
}


您还可以设置超时,并将用户重定向到登录页面.

canActivate(...): Observable<boolean | UrlTree> {
   return this.currentUserSubject.pipe(
      filter(user => !!user), 
      timeout(1000),
      mapTo(true),
      catchError(() => of(this.router.createUrlTree([...])),
      take(1)
   );
}


如果需要考虑其他条件,可以使用


If you need to take into account other conditions, you can use

canActivate(...): Observable<boolean | UrlTree> {
   return this.currentUserSubject.pipe(
      timeout(1000),
      map(user => /* Your condition*/),
      catchError(() => of(this.router.createUrlTree([...])),
      take(1)
   );
}


take(1) pipable 运算符让Guard知道它可以通过完成而继续进行,否则它将无限期地等待 Observable 完成.


The take(1) pipable operator lets the Guard know it can procede by completing, otherwise it will wait indefinitely the Observable completion.

这篇关于Angular 8获取BehaviorSubject的值将返回null的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆