我需要在用户登录后为每个后续请求设置一些授权头。


为特定请求设置头信息,

import {Headers} from 'angular2/http';
var headers = new Headers();
headers.append(headerName, value);

// HTTP POST using these headers
this.http.post(url, data, {
  headers: headers
})
// do something with the response

参考

但是,以这种方式为每个请求手动设置请求头是不可行的。

我如何设置头设置一旦用户登录,也删除注销这些头?


当前回答

HTTP拦截器是实现这一点的正确方法。在这里没有看到关于如何完全实现它的适当文档,所以我包含了谷歌官方指南的链接。在实现之前,我已经通读了文档,因为在安全性和使用多个拦截器包方面存在许多潜在的缺陷。

https://angular.io/guide/http#intercepting-requests-and-responses

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

import { Observable } from 'rxjs';

/** Pass untouched request through to the next request handler. */
@Injectable()
export class NoopInterceptor implements HttpInterceptor {

  intercept(req: HttpRequest<any>, next: HttpHandler):
    Observable<HttpEvent<any>> {
    return next.handle(req);
  }
}

其他回答

迟到总比不到好……=)

您可以采用扩展BaseRequestOptions的概念(从这里https://angular.io/docs/ts/latest/guide/server-communication.html#!#override-default-request-options)并“动态”刷新头(不仅仅是在构造函数中)。你可以像这样使用getter/setter重写“headers”属性:

import { Injectable } from '@angular/core';
import { BaseRequestOptions, RequestOptions, Headers } from '@angular/http';

@Injectable()
export class DefaultRequestOptions extends BaseRequestOptions {

    private superHeaders: Headers;

    get headers() {
        // Set the default 'Content-Type' header
        this.superHeaders.set('Content-Type', 'application/json');

        const token = localStorage.getItem('authToken');
        if(token) {
            this.superHeaders.set('Authorization', `Bearer ${token}`);
        } else {
            this.superHeaders.delete('Authorization');
        }
        return this.superHeaders;
    }

    set headers(headers: Headers) {
        this.superHeaders = headers;
    }

    constructor() {
        super();
    }
}

export const requestOptionsProvider = { provide: RequestOptions, useClass: DefaultRequestOptions };

在这种情况下,扩展BaseRequestOptions可能会有很大帮助。看看下面的代码:

import {provide} from 'angular2/core';
import {bootstrap} from 'angular2/platform/browser';
import {HTTP_PROVIDERS, Headers, Http, BaseRequestOptions} from 'angular2/http';

import {AppCmp} from './components/app/app';


class MyRequestOptions extends BaseRequestOptions {
  constructor () {
    super();
    this.headers.append('My-Custom-Header','MyCustomHeaderValue');
  }
} 

bootstrap(AppCmp, [
  ROUTER_PROVIDERS,
  HTTP_PROVIDERS,
  provide(RequestOptions, { useClass: MyRequestOptions })
]);

这应该包括'My-Custom-Header'在每个调用。

更新:

为了能够在任何时候改变头,而不是上面的代码,你也可以使用下面的代码来添加一个新的头:

this.http._defaultOptions.headers.append('Authorization', 'token');

要删除就可以了

this.http._defaultOptions.headers.delete('Authorization');

还有另一个函数,你可以用来设置值:

this.http._defaultOptions.headers.set('Authorization', 'token');

上述解决方案在typescript上下文中仍然不完全有效。_defaultHeaders是受保护的,不应该这样使用。我会推荐上面的解决方案作为快速修复,但从长远来看,更好的方法是编写自己的包装器来处理http调用,它也可以处理身份验证。以auth0为例,它更好、更简洁。

https://github.com/auth0/angular2-jwt/blob/master/angular2-jwt.ts

Update - June 2018 I see a lot of people going for this solution but I would advise otherwise. Appending header globally will send auth token to every api call going out from your app. So the api calls going to third party plugins like intercom or zendesk or any other api will also carry your authorization header. This might result into a big security flaw. So instead, use interceptor globally but check manually if the outgoing call is towards your server's api endpoint or not and then attach auth header.

像下面这样保持独立的服务怎么样

            import {Injectable} from '@angular/core';
            import {Headers, Http, RequestOptions} from '@angular/http';


            @Injectable()
            export class HttpClientService extends RequestOptions {

                constructor(private requestOptionArgs:RequestOptions) {
                    super();     
                }

                addHeader(headerName: string, headerValue: string ){
                    (this.requestOptionArgs.headers as Headers).set(headerName, headerValue);
                }
            }

当你从另一个地方调用这个时,使用this. httpclientservice。addHeader("Authorization", " holder " + this.tok);

您将看到添加的标题,例如:-授权如下

从Angular 4.3开始,HTTP拦截器现在可以通过新的HttpClient @angular/common/ HTTP使用了。X版本及更高版本。

现在为每个请求添加头文件非常简单:

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

@Injectable()
export class AddHeaderInterceptor implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    // Clone the request to add the new header
    const clonedRequest = req.clone({ headers: req.headers.append('Authorization', 'Bearer 123') });

    // Pass the cloned request instead of the original request to the next handle
    return next.handle(clonedRequest);
  }
}

有一个不可变性的原则,这就是为什么在设置新内容之前需要克隆请求。

由于编辑头部是一个非常常见的任务,实际上有一个快捷方式(在克隆请求时):

const clonedRequest = req.clone({ setHeaders: { Authorization: 'Bearer 123' } });

创建拦截器之后,你应该使用HTTP_INTERCEPTORS提供的方法注册它。

import { HTTP_INTERCEPTORS } from '@angular/common/http';

@NgModule({
  providers: [{
    provide: HTTP_INTERCEPTORS,
    useClass: AddHeaderInterceptor,
    multi: true,
  }],
})
export class AppModule {}

最简单的

创建配置。ts文件

import { HttpHeaders } from '@angular/common/http';

export class Config {
    url: string = 'http://localhost:3000';
    httpOptions: any = {
        headers: new HttpHeaders({
           'Content-Type': 'application/json',
           'Authorization': JSON.parse(localStorage.getItem('currentUser')).token
        })
    }
}

然后在你的服务上,导入配置。ts文件

import { Config } from '../config';
import { HttpClient } from '@angular/common/http';

@Injectable()
export class OrganizationService {
  config = new Config;

  constructor(
    private http: HttpClient
  ) { }

  addData(data): Observable<any> {
     let sendAddLink = `${this.config.url}/api/addData`;

     return this.http.post(sendAddLink , data, this.config.httpOptions).pipe(
       tap(snap => {
      return snap;
        })
    );
 } 

我认为这是最简单和最安全的。