khegay
@khegay
Founder, Garuna

Как правильно использовать BehaviorSubject/Observable в guard?

Приложение на Ionic 5 / Angular 9.

Для хранения данных используется Ionic Data Storage.

auth.guard выглядит так:
import { Injectable } from '@angular/core';
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';

import { AuthService } from '@app/_services'

@Injectable({
    providedIn: 'root'
})

export class AuthGuard implements CanActivate {

    constructor(
        private router: Router,
        private authService: AuthService
    ) { }

    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
        const accessToken = this.authService.currentTokenValue;

        if(accessToken) {
            return true;
        }

        this.router.navigate(['/login'])
        return false;
    }
}


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

import { Storage } from '@ionic/storage'

import { BehaviorSubject, Observable, from } from 'rxjs'
import { map } from 'rxjs/operators';

import { Token } from '@app/_models'
import { environment } from '@env/environment';

@Injectable({
    providedIn: 'root'
})

export class AuthService {

    currentTokenSubject = new BehaviorSubject(null)

    constructor(
        private http: HttpClient,
        private storage: Storage,
    ) {
        this.getToken()
    }

    getToken() {
        this.storage.get('accessToken').then(res => {
            if (res) {
                this.currentTokenSubject.next(res)
            }
        })
    }

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


Суть проблемы:
Метод get() Ionic Data Storage возвращает промис и мне нужно дождаться резолва. Но вся остальная структура работает на Observable.

Получаю что:
Инитициализируется приложение, проходит проверка auth.guard и currentTokenValue() возвращает null. Проверка не проходит и происходит редирект на страницу логина, но промис то реализован и token получен и пользователь может дальше использовать приложение, так как проверка auth.guard возвращает true.

Как правильно все это подружить?
  • Вопрос задан
  • 323 просмотра
Пригласить эксперта
Ответы на вопрос 1
Xuxicheta
@Xuxicheta Куратор тега Angular
инженер

Инитициализируется приложение, проходит проверка auth.guard и currentTokenValue() возвращает null

Получите токен до запуска приложения, с помощью APP_INITIALIZER, он как раз промис юзает.
Например как тут https://blog.zverit.com/frontend/2017/06/17/app-in...

А вообще промис и обсервабл легко конвертировать туда-сюда.

И гард тоже работает с промисом, я бы в нем сразу Data Storage и использовал, а сервис только чтобы обращаться к бэку. Ангуляр вообще много где с промисом может работать, просто это обычно не используется, поэтому не фигурирует в гайдах.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы