Boa noite pessoal, Boa noite Flavio,
Fiz o curso de MEAN usando Angular 2 que por sua vez não possui o interceptors. Então me virei aqui e consegui fazer funcionar. Para ajudar vou divulgar as alterações que fiz aqui para quem mais quiser saber como.
Primeira alteração que fiz foi sobreescrever o XHRBackend, ele é um componente resposável por criar a conexão. E nele que adiciono os Headers necessários
import { Injectable } from '@angular/core';
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';
@Injectable()
export class ExtendedXHRBackend extends XHRBackend {
constructor(browserXhr: BrowserXhr, baseResponseOptions: ResponseOptions, xsrfStrategy: XSRFStrategy) {
super(browserXhr, baseResponseOptions, xsrfStrategy);
}
createConnection(request: Request) {
let token = localStorage.getItem('token');
request.headers.set('x-access-token', `${token}`);
request.headers.set('Content-Type', 'application/json');
let xhrConnection = super.createConnection(request);
xhrConnection.response = xhrConnection.response.catch((error: Response) => {
if (error.status === 401 || error.status === 403) {
console.log('acesso não autorizado');
localStorage.removeItem('token');
}
return Observable.throw(error);
});
return xhrConnection;
}
}
Para que ele injete essa classe precisamos adicionar no AppModule
providers: [{ provide: XHRBackend, useClass: ExtendedXHRBackend }]
Ótimo isso já funcionaria para adicionar no request! Mas como redirecionar para o Login?
O Angular 2 possui em suas rotas o atributo canActivate
que recebe um Array de classes que implementam CanActivate
.
Então criamos o nosso Guarda
import { Injectable } from '@angular/core';
import { Router, CanActivate } from '@angular/router';
import { UserService } from './user.service';
@Injectable()
export class LoggedInGuard implements CanActivate {
constructor(private user: UserService, private router: Router) {}
canActivate() {
let isLoggedIn = this.user.isLoggedIn();
if(!isLoggedIn){
this.router.navigate(['']);
}
return isLoggedIn;
}
}
E usamos em nossas rotas (fiz algumas alterações)
const appRoutes: Routes = [
{ path: '', component: LoginComponent },
{ path: 'cadastro', component: CadastroComponent, canActivate: [LoggedInGuard] },
{ path: 'cadastro/:id', component: CadastroComponent, canActivate: [LoggedInGuard] },
{ path: 'home', component: ListagemComponent, canActivate: [LoggedInGuard] },
{ path: '**', component: LoginComponent, canActivate: [LoggedInGuard] }
];
A classe UserService é a responsável por autenticar e informar se o usuário esta logado ou não
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { Usuario } from '../login/login.component';
import { Observable } from 'rxjs';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
@Injectable()
export class UserService {
private url: string = 'v1/autentica';
private _loggedIn: BehaviorSubject<boolean> = new BehaviorSubject(false);
public loggedIn: Observable<boolean> = this._loggedIn.asObservable();
constructor(private http: Http) { }
autentica(usuario: Usuario) {
return this.http
.post(this.url, JSON.stringify(usuario))
.map((res) => {
var token = res.headers.get('x-access-token');
if (token) {
this._loggedIn.next(true);
localStorage.setItem('token', token);
}
});
}
logout() {
localStorage.removeItem('token');
}
isLoggedIn() {
let token = localStorage.getItem('token');
if(token){ //essa atribuição é feita para atualizar a variavel e o resto do sistema ser notificado
this._loggedIn.next(true);
} else {
this._loggedIn.next(false);
}
return this._loggedIn.getValue();
}
}
Observe que usei o objeto BehaviorSubject
, não entrarei em detalhes aqui, mas ele é e gera um observable que permite que outras classes possam saber das mudanças. Mas para que fazer isso? Nesse caso foi um capricho para permitir que a navbar fosse exibida apenas se o usuário estivesse logado. Para isso é só adicionar o UserService
no AppComponent
constructor(private user: UserService){ }
e utiliza-lo no html
<nav class="navbar navbar-default" *ngIf="user.loggedIn | async" >
<ul class="nav navbar-nav">
<li><a [routerLink]="['/cadastro']">Nova</a></li>
<li><a [routerLink]="['/home']">Home</a></li>
</ul>
</nav>
<router-outlet></router-outlet>
o pipe async fara o subcripte na váriavel user.loggedIn, portanto toda vez que a váriavel mudar será refletida na navbar
Obs Não esqueçam de adicionar o LoggedInGuard e UserServide no AppModule. O resultado final fica assim.
providers: [{ provide: XHRBackend, useClass: ExtendedXHRBackend },
LoggedInGuard,
UserService],
Fica aí minha contribuição com o curso. Espero que seja útil.
Abraços