【问题标题】:Angular5 HttpInterceptor depending on the result of an ObservableAngular5 HttpInterceptor 取决于 Observable 的结果
【发布时间】:2018-08-21 16:26:34
【问题描述】:

我正在尝试使用 Angular5 实现 HttpInterceptor 在所有 HTTP 请求中注入 Authorization 标头。

我依靠第三方库(ADAL,这里称为 AuthService)公开了一个 acquireToken() 方法来获取用于承载授权的令牌。

问题是 aquireToken() 返回一个 observable,我必须订阅才能获得我需要的真实字符串。

因此,我的代码从不注入标头,我想是因为next.handle()acquireToken() 返回任何值之前执行。

如何确保仅在检索到令牌后才调用下一个处理程序?

import { Injectable, Injector } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';

import {AuthService} from 'mylibrary';

@Injectable()
export class MyInterceptor implements HttpInterceptor {

    constructor(private auth: AuthService) { }

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

        let headers = req.headers || new HttpHeaders();

        this.auth.acquireToken(req.url)
            .subscribe((token: string) => {
                headers = headers.append('Authorization', 'Bearer ' + token);
            });

        return next.handle(req.clone({ headers: headers }));
    }
}

【问题讨论】:

    标签: angular5 angular-http-interceptors adal.js angular-observable


    【解决方案1】:

    这段代码可以完成这项工作,诀窍是使用mergeMap

    import { Injectable, Injector } from '@angular/core';
    import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpHeaders } from '@angular/common/http';
    import { Observable } from 'rxjs/Observable';
    import { AdalService } from './adal.service';
    import 'rxjs/add/operator/mergeMap';
    
    @Injectable()
    export class AdalInterceptor implements HttpInterceptor {
    
        constructor(private adal: AdalService) { }
    
        intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    
            // if the endpoint is not registered then pass
            // the request as it is to the next handler
            const resource = this.adal.GetResourceForEndpoint(req.url);
            if (!resource) {
                return next.handle(req.clone());
            }
    
            // if the endpoint is registered then acquire and inject token
            let headers = req.headers || new HttpHeaders();
            return this.adal.acquireToken(resource)
                .mergeMap((token: string) => {
                    // if the user is not authenticated then drop the request
                    if (!this.adal.userInfo.authenticated) {
                        throw new Error('Cannot send request to registered endpoint if the user is not authenticated.');
                    }
    
                    // inject the header
                    headers = headers.append('Authorization', 'Bearer ' + token);
                    return next.handle(req.clone({ headers: headers }));
                }
            );
        }
    }
    

    【讨论】:

    • 您好朋友,我很难理解mergeMap 运算符的使用,以至于我到这个问题到处寻找信息。我知道它用于混合两个或多个 observables 并且只获得一个。但我见过他们将其与单个可观察对象一起使用的代码,这让我感到困惑。
    • 仅供参考,如果是可观察的,请添加return this.adal.acquireToken(resource).pipe(mergeMap(...))
    【解决方案2】:

    可能的问题在这里

     constructor(private auth: AuthService) { }
    

    提供者在拦截器中不可用

    解决方案

    使用Injector 注入您的服务

    // 1. import the injector
    import { Injectable, Injector } from '@angular/core';
    // 2. create a constant of your service
    private auth: AuthService;
    // 3. add injector into contsructor; remove authService from constructor
    constructor(private injector: Injector) { }
    // 4. now create instance of your service inside intercept()
    intercept() {
    const auth = this.injector.get(AuthService);
    // 5. now call method on this auth object
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-12-07
      • 2012-05-29
      • 2018-09-15
      • 1970-01-01
      • 1970-01-01
      • 2020-10-02
      • 1970-01-01
      • 2019-12-05
      相关资源
      最近更新 更多