enter image description here

Вызов GetData из контроллера компонента выполняется слишком рано, я бы хотел, чтобы он дождался окончания идентификации перед запуском.

При загрузке страницы происходит обращение к серверу для идентификации:

return this.http.get<AuthInfo>('.../Auth/login').pipe(
  map((authInfo: AuthInfo) => {
    // ... authentification completed
    return authInfo;
  }),
);

Затем из нескольких других компонентов они смогут вызывать сервер: (с ранее предоставленным токеном JWT)

this.serviceA.methodB().subscribe(
  result => { ... }
)
methodB(): Observable<any> {
  return this.http.get<any>('.../Data/GetData').pipe(
    map(result => {
            ...
      return result;
    }),
  );
}

Я хочу, чтобы methodB вызывался только после завершения идентификации.

Поэтому, если вызывается какой-либо метод, он должен иметь возможность приостановить, если процесс идентификации не завершен.

Сложность здесь в том, что methodB вызывается из других мест во время или после выполнения метода входа в систему.

Возможно ли это с RxJs?

0
A. Morel 5 Июл 2021 в 21:16

3 ответа

Лучший ответ

Вы можете предоставить информацию для аутентификации в BehaviorSubject:

class AuthenticationService {
  private subject = new BehaviorSubject(null);
  public info = subject.asObservable();

  authenticate() {
    this.http.get<AuthInfo>('.../Auth/login').subscribe(x => this.subject.next(x), e => this.subject.error(e))
  }
}

Звоните authenticate в любое место в приложении (например, по кнопке входа)

Затем я предлагаю вам использовать перехватчик, чтобы убедиться, что запросы аутентифицируются перед отправкой:

class AuthenticationInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return authenticationService.info.pipe(
      tap(x => /* If you need to attach the JWT to an HTTP header, do it there */),
      switchMap(() => next.handle(req))
    )
  }
}
2
Guerric P 5 Июл 2021 в 18:51

Вы можете предоставить JWT-токен как ReplaySubject в рамках какой-либо службы (возможно, вашего AuthenticationService, если он у вас есть). Затем вы можете использовать HttpInterceptor, чтобы перехватывать каждый запрос HttpRequest из вашего приложения и добавьте токен JWT в заголовки запроса.

class AuthenticationService {
  public token = new ReplaySubject<string>(1)

  public login() {
    // your login logic here
    this.token.next(theToken)
  }
}
class AuthInterceptor implements HttpInterceptor {
  constructor (private authService: AuthService) {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return this.authService.token.pipe(
      mergeMap(token => {
        req = req.clone({
          headers: new HttpHeaders({
            'Authorization': `bearer ${token}`,
          })
        });
        return next.handle(req);
      })
    )
  }
}

Обратите внимание: я еще не тестировал этот код и не уверен на 100%, что ReplaySubject - правильный выбор здесь. Но лучше использовать HttpInterceptor и общую службу для вашего токена.

Возможно, вам также понадобится дополнительная логика в вашем AuthInterceptor, чтобы не перехватывать запрос входа в систему и другие запросы в вашем приложении, которым не нужен токен.

Инструкции по предоставлению и использованию перехватчиков см. В Руководстве по клиенту Angular Http .

1
Maximilian Ochs 5 Июл 2021 в 18:48

В службе авторизации:

{
    private isAuthCompleted:boolean = false;
    private emitter: EventEmitter<boolean> = new EventEmitter();
  
    getEmitter(){
        return emitter;
    }        

    getAuthComplete(){
        return this.isAuthCompleted 
    }

    authoriztion(){
        return this.http.get<AuthInfo>('.../Auth/login').pipe(
        map((authInfo: AuthInfo) => {
            // ...
            this.isAuthCompleted =  true;  //At end of authorization
            return authInfo;
        }),);
    }
}

Во второй службе:

// If auth service comes later, subscribe and wait
this.serviceA.methodB().subscribe(
  result => {
      emitter.subscribe((event)=>{
          if(event)
          //Resume
      })  
  }

  //if auth service was already done, trigger the emitter
  if(AuthService.getAuthComplete()){
      emitter.emit(true);
  }
)
-2
Abhay Aravinda 5 Июл 2021 в 18:58