Descrição
A melhor solução que encontrei é substituir o de XHRBackendmodo que o status de resposta HTTP 401e 403leve a uma ação específica.
Se você manipular sua autenticação fora de seu aplicativo Angular, poderá forçar uma atualização da página atual de forma que seu mecanismo externo seja acionado. Eu detalho essa solução na implementação abaixo.
Você também pode encaminhar para um componente dentro de seu aplicativo de forma que seu aplicativo Angular não seja recarregado.
Implementação
Angular> 2.3.0
Graças a @mrgoos, aqui está uma solução simplificada para angular 2.3.0+ devido a uma correção de bug no angular 2.3.0 (consulte o problema https://github.com/angular/angular/issues/11606 ) estendendo diretamente o Httpmódulo.
import { Injectable } from '@angular/core';
import { Request, XHRBackend, RequestOptions, Response, Http, RequestOptionsArgs, Headers } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';
@Injectable()
export class AuthenticatedHttpService extends Http {
constructor(backend: XHRBackend, defaultOptions: RequestOptions) {
super(backend, defaultOptions);
}
request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
return super.request(url, options).catch((error: Response) => {
if ((error.status === 401 || error.status === 403) && (window.location.href.match(/\?/g) || []).length < 2) {
console.log('The authentication session expires or the user is not authorised. Force refresh of the current page.');
window.location.href = window.location.href + '?' + new Date().getMilliseconds();
}
return Observable.throw(error);
});
}
}
O arquivo do módulo agora contém apenas o seguinte provedor.
providers: [
{ provide: Http, useClass: AuthenticatedHttpService }
]
Outra solução usando roteador e um serviço de autenticação externa é detalhada na essência a seguir por @mrgoos.
Angular pré-2.3.0
A implementação a seguir funciona para Angular 2.2.x FINALe RxJS 5.0.0-beta.12.
Ele redireciona para a página atual (mais um parâmetro para obter um URL exclusivo e evitar o armazenamento em cache) se um código HTTP 401 ou 403 for retornado.
import { Request, XHRBackend, BrowserXhr, ResponseOptions, XSRFStrategy, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';
export class AuthenticationConnectionBackend extends XHRBackend {
constructor(_browserXhr: BrowserXhr, _baseResponseOptions: ResponseOptions, _xsrfStrategy: XSRFStrategy) {
super(_browserXhr, _baseResponseOptions, _xsrfStrategy);
}
createConnection(request: Request) {
let xhrConnection = super.createConnection(request);
xhrConnection.response = xhrConnection.response.catch((error: Response) => {
if ((error.status === 401 || error.status === 403) && (window.location.href.match(/\?/g) || []).length < 2) {
console.log('The authentication session expires or the user is not authorised. Force refresh of the current page.');
window.location.href = window.location.href + '?' + new Date().getMilliseconds();
}
return Observable.throw(error);
});
return xhrConnection;
}
}
com o seguinte arquivo de módulo.
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HttpModule, XHRBackend } from '@angular/http';
import { AppComponent } from './app.component';
import { AuthenticationConnectionBackend } from './authenticated-connection.backend';
@NgModule({
bootstrap: [AppComponent],
declarations: [
AppComponent,
],
entryComponents: [AppComponent],
imports: [
BrowserModule,
CommonModule,
HttpModule,
],
providers: [
{ provide: XHRBackend, useClass: AuthenticationConnectionBackend },
],
})
export class AppModule {
}