Angular 6-Auth令牌拦截器未添加标头

时间:2018-07-20 17:21:04

标签: angular typescript

在过去两天中,我使用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
        }
      }
    });
  }
}

如果我注销request,则request.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);
  }
}

4 个答案:

答案 0 :(得分:1)

我使用的完整解决方案:

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);
  }
}

答案 1 :(得分:0)

所以我在这里看到的第一个问题是,如果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);
    }
}

答案 2 :(得分:0)

您可以尝试使用它的简单版本。(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在这里(根据您的情况)是指向 clone (克隆)(这意味着每当我们收到请求时,我们都会对其进行克隆,然后执行我们想要的任何操作并将其发送出去)。
我们可以为更多的标头添加更多的数据
它将被发送出去,然后最终从Api返回并返回
将句柄问题留给调用service的{​​{1}}(例如:httpRequest,...)。

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

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

答案 3 :(得分:0)

对于那些关注msal角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

中的通配符投票