【问题标题】:Angular 6 - Auth token interceptor not adding headersAngular 6 - 身份验证令牌拦截器不添加标头
【发布时间】:2018-12-29 01:28:07
【问题描述】:

在过去的两天里,我使用 Angular 6 尝试了许多不同的方法,这篇文章的最新版本是:https://stackoverflow.com/a/47401544。但是,仍然没有在请求上设置标头。

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

@Injectable()
export class AuthTokenInterceptor implements HttpInterceptor {
  constructor() {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(req).do((event: HttpEvent<any>) => {
      if (localStorage.getItem('id_token') != null) {
        // Clone the request to add the new header.
        const request = req.clone({
          setHeaders: {
            'Content-Type' : 'application/json; charset=utf-8',
            'Accept'       : 'application/json',
            'Authorization': `Bearer ${localStorage.getItem('id_token')}`
          }
        });
        return next.handle(request);
      }
    }, (err: any) => {
      if (err instanceof HttpErrorResponse) {
        if (err.status === 401) {
          console.log('redirect auth interceptor')
          // do a redirect
        }
      }
    });
  }
}

如果我注销 requestrequest.headers.lazyUpdate 数组将更新 3 个项目,但我在它拦截的请求中看不到 Authorization 标头。

request.headers.lazyUpdate:

{name: "Content-Type", value: "application/json; charset=utf-8", op: "s"}
{name: "Accept", value: "application/json", op: "s"}
{name: "Authorization", value: "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2Mzh9.tLTmPK46NhXSuqoCfZKgZcrQWzlNqLMI71-G0iy3bi8", op: "s"}

request.headers.headers 是空的——这可能是问题吗?)

app.module.ts:

providers: [
    {provide: HTTP_INTERCEPTORS, useClass: AuthTokenInterceptor, multi: true},
  ],

让我认为这是一个拦截器问题的原因是,如果我手动将标头添加到请求中,我不会得到 401 并且请求会返回正确的数据和 200

return this.http.get(environment.API_URL + 'list/supervise/' + encodeURIComponent(id),
      {headers: new HttpHeaders().set('Authorization', `Bearer ${localStorage.getItem('id_token')}`)}).pipe(
        map((res: any) => res.data)
    );

有什么我可能忽略的吗?谢谢。

编辑:

正如我在下面的评论中提到的,我两次返回 next.handle。这是我最终采用的解决方案:

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

@Injectable()
export class AuthTokenInterceptor implements HttpInterceptor {
  constructor() {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const token = localStorage.getItem('id_token');

    req = req.clone({
      setHeaders: {
        'Authorization': `Bearer ${token}`
      },
    });

    return next.handle(req);
  }
}

【问题讨论】:

    标签: angular typescript


    【解决方案1】:

    您可以尝试一个更简单的版本。(just like your reference link does)

      intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        const jwt = localStorage.getItem('id_token');
        if (!!jwt) {
         req = req.clone({
           setHeaders: {
             Authorization: `Bearer ${jwt}`
           }
         });
       }
       return next.handle(req);
     }
    

    您不必在此处处理error
    因为这里intercepter 的意义(在您的上下文中)是克隆(这意味着每当我们接受请求时,我们都会克隆它,然后做我们想做的任何事情并将其发送出去)。
    我们可以添加更多标题更多数据
    它会被送走,然后最终从 Api 返回回来
    并将句柄问题留给调用httpRequestservice(例如:then, catch, pipe,...)。

    再次,您在app.module.ts 中声明了这一点,这意味着您的应用程序中的requestto api 中的all 将被拦截,如果我想处理带有错误消息Nothing here 的特定请求怎么办?如果你做一些复杂的逻辑,它可能会影响所有的请求。

    关于你上面的代码,我没有尝试过,但我认为当你这样嵌套时它们可能发生了错误,你应该把断点放在它们并尝试调试发生的事情。

    【讨论】:

    • "您不必在这里处理错误" ,但他可以这样做,next.handle(req) 返回一个 Observable,因此他可以执行类似 next.handle(req).pipe(地图(x => { ... }))
    • 我想我不小心组合了一些方法并搞砸了。我错误地做了return next.handle(req).do((event: HttpEvent&lt;any&gt;) =&gt; {return next.handle(request);
    • 检查 req.url 是否是您想要的 API 也很重要。由于令牌是敏感信息,您不希望将令牌发送到您的 Angular 应用程序可能调用的所有其他第 3 方 URL。
    【解决方案2】:

    我使用的完整解决方案:

    import {Injectable} from '@angular/core';
    import {
      HttpEvent,
      HttpInterceptor,
      HttpHandler,
      HttpRequest
    } from '@angular/common/http';
    import { Observable } from 'rxjs';
    
    @Injectable()
    export class AuthTokenInterceptor implements HttpInterceptor {
      constructor() {}
    
      intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        const token = localStorage.getItem('id_token');
    
        req = req.clone({
          setHeaders: {
            'Authorization': `Bearer ${token}`
          },
        });
    
        return next.handle(req);
      }
    }
    

    【讨论】:

    • 对于 MSAL 1.x,如果密钥是 msal.idtoken,则此方法有效
    【解决方案3】:

    所以我在这里看到的第一个问题是,如果 localStorage 中没有值,你就不会返回。我会像这样构造拦截器:

    export class AuthInterceptor implements HttpInterceptor {
    
        private APIToken = null;
        private defaultApplicationHeaders = {
            'Content-Type': 'application/json'
        }
    
        buildRequestHeaders():HttpHeaders {
    
            let headers = this.defaultApplicationHeaders;
    
            // set API-Token if available
            if(this.APIToken !== null) {
                let authHeaderTpl = `Bearer ${this.APIToken}`;
                headers['Authorization'] = authHeaderTpl
            }
    
            return new HttpHeaders(headers);
        }
    
        constructor() {
            this.APIToken = localStorage.getItem('id_token')
        }
    
        intercept(req: HttpRequest<any>, next: HttpHandler) {
            const headers = this.buildRequestHeaders();
            const authReq = req.clone({ headers });
    
            return next.handle(authReq);
        }
    }
    

    【讨论】:

      【解决方案4】:

      对于那些关注 msal-angular MsalHttpInterceptor 的人。 现在我自己实现了 MsalInterceptor。
      这是我的自定义代码块:

      // #region own workaround in order not to put every api endpoint url to settings
      if (!scopes && req.url.startsWith(this.settingsService.apiUrl)) {
        scopes = [this.auth.getCurrentConfiguration().auth.clientId];
      }
      // #endregion
      
      // If there are no scopes set for this request, do nothing.
      if (!scopes) {
        return next.handle(req);
      }
      

      PS:在 protectedResourceMap https://github.com/AzureAD/microsoft-authentication-library-for-js/issues/1776 中投票给通配符

      【讨论】:

        猜你喜欢
        • 2016-02-28
        • 1970-01-01
        • 2020-06-06
        • 1970-01-01
        • 2020-08-22
        • 2017-11-16
        • 2018-11-20
        • 2017-02-01
        • 2015-03-24
        相关资源
        最近更新 更多