Angular 6 - 身份验证令牌拦截器不添加标头

Angular 6 - Auth token interceptor not adding headers

提问人:kriskanya 提问时间:7/21/2018 最后编辑:kriskanya 更新时间:6/18/2020 访问量:20430

问:

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

如果我注销,数组正在用 3 个项目更新,但我在它拦截的请求中没有看到标头。requestrequest.headers.lazyUpdateAuthorization

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},
  ],

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

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);
  }
}
角度 打字稿

评论


答:

1赞 enno.void 7/21/2018 #1

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

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);
    }
}
3赞 lupa 7/21/2018 #2

您可以尝试更简单的版本。(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);
 }

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

同样,您声明了您的应用程序中 to api 的意思将被拦截,如果我想处理带有错误消息的特定请求怎么办?,如果您执行一些复杂的逻辑,它可能会影响所有请求。

关于你上面的代码,我还没有尝试过,但我认为当你这样嵌套时,它们可能会出错,你应该把断点放在他们身上,并尝试调试发生了什么。
app.module.tsallrequestNothing here

评论

0赞 enno.void 7/21/2018
“你不必在这里处理错误”,但他可以这样做,next.handle(req) 返回一个 Observable,所以他可以做类似 next.handle(req).pipe(map(x => { ... }))
0赞 kriskanya 7/21/2018
我想我不小心结合了几种方法并搞砸了。我做错了.return next.handle(req).do((event: HttpEvent<any>) => {return next.handle(request);
0赞 Nagesh Andani 6/4/2021
检查 req.url 是否是您想要的 API 也很重要。由于令牌是敏感信息,因此您不希望将令牌发送到 Angular 应用程序可能调用的所有其他第三方 URL。
3赞 kriskanya 10/10/2018 #3

我选择的完整解决方案:

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

评论

0赞 ランス 1/6/2021
对于 MSAL 1.x,如果密钥为 msal.idtoken,则此操作有效
0赞 Cyclion 6/18/2020 #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 中为通配符投票