Angular - Как добавить токен доступа из наблюдаемого в исходящий HTTP-запрос? - PullRequest
5 голосов
/ 13 марта 2019

в моем UserService У меня есть объект Observable пользователя, который содержит UserModel пользователя, вошедшего в систему. Для тестирования я реализовал в ngOnInit() процесс входа в систему:

this.userService.authenticate('###', '###')
   .subscribe(res => console.log('authenticated'));
private userSource = new BehaviorSubject<UserModel>(null);
   public user = this.userSource.asObservable();

My UserModel предоставляет атрибут authKey, который используется для аутентификации API.

В моем ProjectService я хотел бы сделать запрос API; Для этого необходим ключ API, сохраненный в UserModel. Можно было бы просто подписать атрибут пользователя, но я читал о том, как избегать подписок внутри сервисов.

Вопрос

Как я могу связать эту подписку с каналами / отображением? Мой подход был следующий код; но это похоже на плохой код.

suggest(term: string): Observable<ProjectModel[]> {
      return this.userSrv.user.pipe(
         mergeMap((user: UserModel) => {
            const options = {params: {'access-token': user.accessToken}};

            return this.http.get<ProjectModel[]>(this.conf.url, options).pipe(
               map(response => {
                  // mapping the projects ...
                  return projects;
               })
            );
         })
      );
   }

Ответы [ 2 ]

1 голос
/ 13 марта 2019

Как уже говорилось в предыдущем ответе, HTTP Interceptor лучше всего подходит для вашего случая использования.

Основная идея будет выглядеть так:

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

function isLoginRequest(req: HttpRequest<any>): boolean {
    // implement
}

@Injectable()
export class AccessTokenInterceptor implements HttpInterceptor {
  constructor(private readonly userService: UserService){}

  intercept(req: HttpRequest<any>, next: HttpHandler):
    Observable<HttpEvent<any>> {
    if(isLoginRequest(req)) return next.handle(req);
    return this.userService.user.pipe(
      map(user => req.clone({setParams:{'access-token': user.accessToken}})),
      mergeMap(req => next.handle(req))
    );
  }
}

Не забудьте зарегистрировать этот перехватчик, как показано в документации.

При использовании этого ваша оригинальная сервисная функция уменьшается до:

suggest(term: string): Observable<ProjectModel[]> {
  return this.http.get<ProjectModel[]>(this.conf.url).pipe(
           map(response => {
              // mapping the projects ...
           })
        );
}
1 голос
/ 13 марта 2019

Вместо того, чтобы передавать каждому запросу токен доступа, вы должны использовать HttpInterceptor: https://angular.io/api/common/http/HttpInterceptor. Это добавит AccessToken каждый HTTP-запрос, который вы делаете. Сохраните пользователя в BehaviorSubject в вашем UserService и используйте его внутри Interceptor.

После этого ваша функция будет выглядеть так:

suggest(term: string): Observable<ProjectModel[]> {
    return this.http.get<ProjectModel[]>(this.conf.url + '/my-endpoint');
}
...