【问题标题】:How to use Ionic Data Storage with BehaviorSubject and Observable如何将离子数据存储与 BehaviorSubject 和 Observable 一起使用
【发布时间】:2020-06-04 05:08:17
【问题描述】:

我正在尝试使用 Angular 9 / Ionic 5 创建应用程序

我正在使用Ionic Data Storage

所以,我的 auth.service.ts 看起来像:

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';

import { Storage } from '@ionic/storage'

import { BehaviorSubject, Observable, from } from 'rxjs'

@Injectable({
    providedIn: 'root'
})

export class AuthService {

    private currentTokenSubject: BehaviorSubject<string>
    public currentToken: Observable<string>

    constructor(
        private http: HttpClient,
        private storage: Storage,
    ) {
        this.getToken()
            .then(res => {
                this.currentTokenSubject = new BehaviorSubject(res)
                this.currentToken = this.currentTokenSubject.asObservable()
            }
        )
    }

    async getToken() {
        return await this.storage.get('accessToken')
    }

    public get currentTokenValue(): string {
        return this.currentTokenSubject.value;
    }

    login(username: string, password: string) {
        const headers = new HttpHeaders({
            'Content-Type': 'application/json',
            'Accept': 'application/json',
            'Authorization': 'Basic ' + btoa(username + ':' + unescape(encodeURIComponent(password)))
        })

        return this.http.post<Token>(`${environment.apiUrl}/auth/signin`, { }, { headers })
            .pipe(map((res: Token) => {
                let token = res.token
                // store user details and jwt token in local storage to keep user logged in between page refreshes
                this.storage.set('accessToken', token);
                return token;
            }));
    }

    logout() {
        // remove user from local storage to log user out
        this.storage.remove('accessToken');
        this.currentTokenSubject.next(null);
    }
}

jwt.interceptor.ts 看起来像:

import { Injectable } from '@angular/core'
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http'
import { Observable } from 'rxjs'

import { AuthService } from '@app/_services'

@Injectable()
export class JwtInterceptor implements HttpInterceptor {
    constructor(
        private authService: AuthService
    ) { }

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        // add authorization header with jwt token if available
        const currentToken = this.authService.currentTokenValue;

        if (currentToken) {
            request = request.clone({
                setHeaders: {
                    Authorization: `Bearer ${currentToken}`
                }
            });
        }

        return next.handle(request);
    }
}

所以,当我尝试调用服务时,我得到了错误,因为 Ionic Storage 返回 Observable:

Error: Uncaught (in promise): TypeError: Cannot read property 'value' of undefined
TypeError: Cannot read property 'value' of undefined
at AuthService.get currentTokenValue [as currentTokenValue] (auth.service.ts:39)

问题是:从 Ionic Storage 获取价值并使用它的正确方法是什么?

【问题讨论】:

    标签: angular jwt observable behaviorsubject


    【解决方案1】:

    在分配任何值之前,您尝试访问BehaviorSubjectvalue getter 的问题。最好避免使用 value getter 并订阅 observable 以保持异步。试试下面的

    auth.service.ts

    export class AuthService {
      private currentTokenSubject = new BehaviorSubject<string>(null); // <-- assign default value here
    
      constructor(
        private http: HttpClient,
        private storage: Storage,
      ) {
        this.getToken().then(
          res => {
            this.currentTokenSubject.next(res);               // <-- push token to the observable
          }
        );
      }
    
      async getToken() {
        return await this.storage.get('accessToken');
      }
    
      public get currentTokenValue(): Observable < string > {
        return this.currentTokenSubject.asObservable();        // <-- return observable here
      }
    
      login(username: string, password: string) {
        const headers = new HttpHeaders({
          'Content-Type': 'application/json',
          'Accept': 'application/json',
          'Authorization': 'Basic ' + btoa(username + ':' + unescape(encodeURIComponent(password)))
        })
    
        return this.http.post<Token>(`${environment.apiUrl}/auth/signin`, {}, { headers }).pipe(
          map((res: Token) => {
            let token = res.token;
            // store user details and jwt token in local storage to keep user logged in between page refreshes
            this.storage.set('accessToken', token);
            this.currentTokenSubject.next(token);              // <-- also push new token here?
            return token;
          }));
      }
    
      logout() {
        // remove user from local storage to log user out
        this.storage.remove('accessToken');
        this.currentTokenSubject.next(null);
      }
    }
    

    现在您需要订阅函数currentTokenValue() 来获取令牌。

    一些组件/服务

    export class SomeComponent implements OnInit {
      token: string;
    
      ngOnInit() {
        this.authService.currentTokenValue().subscribe(
          token => { 
            if(token) {       // <-- check if token valid because it can also be null
              this.token = token;
            }
          }
        );
      }
    }
    

    【讨论】:

    • 是的,但我无法在 auth.guard 中调用订阅
    • 在这种情况下,现在尝试使用getValue() 方法。早些时候它可能会抛出一个错误,因为 currentTokenSubject 没有在定义中初始化。
    猜你喜欢
    • 1970-01-01
    • 2020-08-02
    • 1970-01-01
    • 2020-01-06
    • 1970-01-01
    • 1970-01-01
    • 2019-01-23
    • 2016-03-30
    • 2015-03-24
    相关资源
    最近更新 更多