ОБНОВЛЕНИЕ: (обновления идут вверху)
Поскольку я использую 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