
3.0 / 5
Hola buenas a todos, autenticar nuestra aplicación en angular es algo que tenemos que hacer desde el principio, hoy vamos a ver este tema para tener una app segura.
Desde hace un tiempo se agrego varias herramientas para nuestras peticiones HTTP con un monton de caracterÃsticas muy útiles. Tal vez la caracterÃstica más largamente esperada es la interfaz HttpInterceptor. Hasta hace un tiempo, no habÃa forma de interceptar y modificar solicitudes HTTP de forma global. Esto siempre ha sido posible en AngularJS y el hecho de que haya faltado en Angular 2+ ha sido un punto de fricción con los desarrolladores.
Entonces, ¿por qué son útiles los interceptores HTTP? Hay muchas razones, pero un caso de uso común es adjuntar automáticamente información de autenticación a las solicitudes. Esto puede tomar varias formas diferentes, pero la mayorÃa de las veces implica la incorporación de un token web JSON (u otra forma de token de acceso) como un AuthorizationHeader con el esquema Bearer.
Al manejar la autenticación en una aplicación angular, generalmente es mejor colocar todo lo que necesita en un servicio dedicado. Cualquier servicio de autenticación debe tener unos pocos métodos básicos para permitir a los usuarios iniciar y cerrar sesión. También debe incluir un método para recuperar un JSON Web Token desde donde esté almacenado en el cliente y una forma de determinar si el usuario está autenticado o no.
import { Injectable } from '@angular/core'; import { JhiLanguageService } from 'ng-jhipster'; import { Principal } from '../auth/principal.service'; import { AuthServerProvider } from '../auth/auth-jwt.service'; @Injectable() export class LoginService { constructor( private languageService: JhiLanguageService, private principal: Principal, private authServerProvider: AuthServerProvider ) {} login(credentials, callback?) { const cb = callback || function() {}; return new Promise((resolve, reject) => { this.authServerProvider.login(credentials).subscribe((data) => { this.principal.identity(true).then((account) => { // After the login the language will be changed to // the language selected by the user during his registration if (account !== null) { this.languageService.changeLanguage(account.langKey); } resolve(data); }); return cb(); }, (err) => { this.logout(); reject(err); return cb(err); }); }); } loginWithToken(jwt, rememberMe) { return this.authServerProvider.loginWithToken(jwt, rememberMe); } logout() { this.authServerProvider.logout().subscribe(); this.principal.authenticate(null); } }
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs/Observable'; import { LocalStorageService, SessionStorageService } from 'ngx-webstorage'; import { SERVER_API_URL } from '../../app.constants'; @Injectable() export class AuthServerProvider { constructor( private http: HttpClient, private $localStorage: LocalStorageService, private $sessionStorage: SessionStorageService ) {} getToken() { return this.$localStorage.retrieve('authenticationToken') || this.$sessionStorage.retrieve('authenticationToken'); } login(credentials): Observable<any> { const data = { username: credentials.username, password: credentials.password, rememberMe: credentials.rememberMe }; return this.http.post(SERVER_API_URL + 'api/authenticate', data, {observe : 'response'}).map(authenticateSuccess.bind(this)); function authenticateSuccess(resp) { const bearerToken = resp.headers.get('Authorization'); if (bearerToken && bearerToken.slice(0, 7) === 'Bearer ') { const jwt = bearerToken.slice(7, bearerToken.length); this.storeAuthenticationToken(jwt, credentials.rememberMe); return jwt; } } } loginWithToken(jwt, rememberMe) { if (jwt) { this.storeAuthenticationToken(jwt, rememberMe); return Promise.resolve(jwt); } else { return Promise.reject('auth-jwt-service Promise reject'); // Put appropriate error message here } } storeAuthenticationToken(jwt, rememberMe) { if (rememberMe) { this.$localStorage.store('authenticationToken', jwt); } else { this.$sessionStorage.store('authenticationToken', jwt); } } logout(): Observable<any> { return new Observable((observer) => { this.$localStorage.clear('authenticationToken'); this.$sessionStorage.clear('authenticationToken'); observer.complete(); }); } }
El objetivo es incluir el JWT que está en el almacenamiento local como AuthorizationenHeader en cualquier solicitud HTTP que se envÃe. El primer paso es crear un interceptor. Para hacer esto, crea una clase Injectable que implemente HttpInterceptor.
import { Observable } from 'rxjs/Observable'; import { LocalStorageService, SessionStorageService } from 'ngx-webstorage'; import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http'; import { SERVER_API_URL } from '../../app.constants'; export class AuthInterceptor implements HttpInterceptor { constructor( private localStorage: LocalStorageService, private sessionStorage: SessionStorageService ) { } intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { if (!request || !request.url || (/^http/.test(request.url) && !(SERVER_API_URL && request.url.startsWith(SERVER_API_URL)))) { return next.handle(request); } const token = this.localStorage.retrieve('authenticationToken') || this.sessionStorage.retrieve('authenticationToken'); if (!!token) { request = request.clone({ setHeaders: { Authorization: 'Bearer ' + token } }); } return next.handle(request); } }
Cualquier interceptor que queremos crear necesita implementar la interfaz HttpInterceptor. Esto significa que nuestra nueva clase debe tener un método llamado intercept con los parametros HttpRequest y HttpHandler. El uso de interceptores se trata de cambiar las solicitudes salientes y las respuestas entrantes, pero no podemos alterar la solicitud original: debe ser inmutable. Para hacer cambios, necesitamos clonar el request original.
Al clonar el request original, podemos establecer los encabezados que queremos. En nuestro caso es muy simple: solo queremos agregar un Authorization Header con un esquema de autenticación Bearer seguido del JSON Web Token obtenido mediante localstorage y sessionStorage, mirar codigo propuesto.
Llamar next.handle significa que estamos pasando el control al siguiente interceptor en la cadena, si hay uno.
El interceptor necesita ser agregado a la matriz HTTP_INTERCEPTORS. Esto se hace haciendo que la matriz HTTP_INTERCEPTORS existente use la nueva clase que hemos creado. Agregue esto en el provider del módulo principal de nuestra aplicación.
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppComponent } from './app.component'; import {AppRoutingModule} from './routing/app-routing'; import {HTTP_INTERCEPTORS, HttpClientModule} from '@angular/common/http'; import {VistaModule} from './vista/vista.module'; import {LayoutModule} from './layout/layout.module'; import {AuthInterceptor} from './blocks/interceptor/auth.interceptor'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, AppRoutingModule, HttpClientModule, VistaModule, LayoutModule ], providers: [ { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true } ], bootstrap: [AppComponent] }) export class AppModule { }
Ahora cuando hacemos una solicitud HTTP, el token del usuario se adjuntará automáticamente.
public ping() { this.http.get('https://example.com/api/things') .subscribe( data => console.log(data), err => console.log(err) ); }
Esta solicitud incluirá un Authorization
 al encabezado de la peticion con un valor  Bearer token...
Cabe señalar que el nuevo HttpClient de Angular @angular/common/http se está utilizando aquà y no la clase Http de @angular/http. Si tratamos de hacer solicitudes con la clase Http tradicional , el interceptor no será golpeado.
Al hacer todo esto nos estamos asegurando de que cualquier petición que se ejecute desde la aplicación pase antes por el interceptor, este verifica que en la session o en el localstorage este el token guardado, en el caso de que no este el token la peticion sera denegada, ya que no se adjunta el token a la peticion y tendriamos un error.
Espero les sea de ayuda esto, asà como ami me fue de ayuda.