Angular Круговая зависимость. Сервис -> Государство -> Сервис. Как с этим бороться? - PullRequest
0 голосов
/ 24 марта 2020

ОБНОВЛЕНИЕ: (обновления идут вверху)

Поскольку я использую NGXS, я переделал свою службу / состояние, используя следующий подход: В классе, который вызывал услуга - услуга больше не вызывается. Вместо этого он отправил действие. Таким образом, состояние запускает соответствующий редуктор для этого действия и вызывает метод службы renewAccessToken, добавляя в качестве параметра refreshToken. Это хороший способ, который я сделал.

Но ... У меня все еще есть проблема (совершенно другая проблема). Класс, который отправляет действие, на самом деле является пользовательским HTTP_INTERCEPTOR, и я хочу сделать request.clone (), если токен был успешно обновлен.

Я думаю о разрешениях ... Советы приветствуются.

НАЧАЛЬНЫЙ ВОПРОС:

Я понимаю ошибку. Но я здесь, чтобы спросить у вас совета, как с этим бороться. Как мне изменить свою структуру, используя лучшие практики?

Я использую Ioni c + Angular + NGXS.

Моя текущая идея - взять refreshToken непосредственно из localStorage без введения AuthState в AuthService. Но я думаю, что это не лучший способ справиться с такими проблемами.

Мой текущий код прикреплен ниже:

Состояние :

import { State, Action, StateContext, Selector, Store } from '@ngxs/store';
import { tap, catchError } from 'rxjs/operators';
import { ImmutableContext } from '@ngxs-labs/immer-adapter';
import { AuthModel } from './model';
import { of } from 'rxjs';
import { JwtHelperService } from '@auth0/angular-jwt';
import { AuthService } from 'src/app/services/auth.service';
import {
  TryLogin,
  LoginFailed,
  LoginSucceess,
  TryLogout,
  LogoutSuccess
} from 'src/app/pages/login/store/actions';
import { Injectable } from '@angular/core';
import { UiService } from 'src/app/services/ui.service';
import { Unauthorized } from 'src/app/errors/response-errors/unauthorized';

@State<AuthModel>({
  name: 'auth',
  defaults: {
    token: null,
    refreshToken: null
  }
})
@Injectable()
export class AuthState {
  @Selector()
  static token(state: AuthModel): string | null {
    return state.token;
  }

  @Selector()
  static refreshToken(state: AuthModel): string | null {
    return state.refreshToken;
  }

  @Selector()
  static isAuthenticated(state: AuthModel): boolean {
    if (state.token) {
      const jwtHelper = new JwtHelperService();

      if (!jwtHelper.isTokenExpired(state.token)) {
        return true;
      }
    }
    return false;
  }

  constructor(
    private authService: AuthService,
    private store: Store,
    private uiService: UiService
  ) {}

  @Action(TryLogin)
  @ImmutableContext()
  login({ setState }: StateContext<AuthModel>, { payload }: TryLogin) {
    this.uiService.displayLoading();
    return this.authService.login(payload).pipe(
      catchError(err => {
        this.uiService.dismissLoading();
        if (err instanceof Unauthorized) {
          this.store.dispatch(new LoginFailed());
        }
        return of(null);
      }),
      tap((result: any) => {
        this.uiService.dismissLoading();
        if (result) {
          setState((state: AuthModel) => {
            state.token = result.token;
            state.refreshToken = result.refresh_token;

            return state;
          });
          this.store.dispatch(new LoginSucceess());
        }
      })
    );
  }

  @Action(TryLogout)
  @ImmutableContext()
  logout({ setState }: StateContext<AuthModel>, {}: TryLogout) {
    setState((state: AuthModel) => {
      state.token = null;
      state.refreshToken = null;

      return state;
    });
    this.store.dispatch(new LogoutSuccess());
  }
}

Сервис :

import { Injectable } from '@angular/core';
import { ApiService } from './api.service';
import { HttpClient } from '@angular/common/http';
import { LoginForm } from '../pages/login/interfaces/login-form';
import { AuthState } from '../store/auth/state';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class AuthService extends ApiService {
  refreshToken$: Observable<string>;

  constructor(http: HttpClient) {
    super(http);
  }

  login(credentials: LoginForm) {
    console.log('AuthService:login');
    return this.post('/login', {
      email: credentials.username,
      password: credentials.password
    });
  }

  renewAccessToken(): Observable<any> {
    console.log('AuthService:renewAccessToken');
    return this.post('/renew-access-token', {
      refresh_token: AuthState.refreshToken
    });
  }
}

Ошибка:

[ng] WARNING in Circular dependency detected:
[ng] src/app/services/auth.service.ts -> src/app/store/auth/state.ts -> src/app/services/auth.service.ts
...