El otro día me estaba preguntando cómo hacer para enviar cabeceras de autenticación con Angular en todas mis peticiones HTTP. En AngularJS lo resolvía fácilmente con un interceptor, pero aquí ya no tenemos de eso.

Pese a todo, podemos obrar de una forma muy similar: al constructor de la clase Http se le inyecta una instancia de la clase RequestOptions. Así que sólo tenemos que implementar una clase que la extienda y ahí poner nuestros custom headers.

Antes de implementar esa clase, os presento al servicio AuthService, que se encarga de guardar tokens de autorización:

import {Injectable} from '@angular/core';

@Injectable()
export class AuthService {
  private _token: string = null;

  constructor() {}

  get token(): string {
    return this._token;
  }

  set token(value: string) {
    this._token = value;
  }
}

Ya tenemos nuestro token holder, veamos pues nuestra clase CustomRequestOptions. En muchos ejemplos que he visto por ahí se utiliza el constructor para grabar a fuego las cabeceras que queremos añadir. Como las que introduciremos nosotros dependen de la existencia del token, delegaremos esta decisión al método merge:

import {Injectable} from '@angular/core';
import {
  BaseRequestOptions, RequestOptions, RequestOptionsArgs
} from '@angular/http';
import {AuthService} from './auth.service';

const AUTHORIZATION_HEADER = 'autorization';

@Injectable()
export class CustomRequestOptions extends BaseRequestOptions {

  constructor(private authService: AuthService) {
    super();
  }

  merge(options?: RequestOptionsArgs): RequestOptions {
    if (this.authService.token) {
      this.headers.append(AUTHORIZATION_HEADER, `Bearer ${this.authService.token}`);
    } else {
      this.headers.delete(AUTHORIZATION_HEADER);
    }

    return super.merge(options);
  }
}

El método merge se ejecuta cada vez que se realiza una petición HTTP, y realiza una mezcla de las cabeceras de nuestro CustomRequestOptions con las que se hayan incluido en la petición Http. Así, miraremos primero si hay token para añadir o eliminar la cabecera de autorización.

Ahora, ¿cómo le decimos a Angular que hay que inyectar nuestra clase al constructor de la clase Http? Fácil, recordemos que en la declaración de nuestros módulos podemos utilizar ClassProviders para determinar el uso de nuestra clase cuando se pida un RequestOptions al inyector.

/** ALL NEEDED IMPORTS **/
import {AuthService} from './auth.service';

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, HttpModule],
  providers: [
    AuthService,
    {provide: RequestOptions, useClass: CustomRequestOptions}
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}

Como siempre, dejo una demo jugable que podemos ver en Plunker.

¿Habías tenido una necesidad similar? ¿La habías resuelto de manera similar o de otra forma?

Anuncios