Angular >4.3 & <5.2.3 - JWT 拦截器 - 刷新令牌
Angular >4.3 & <5.2.3 - JWT Interceptor - Refresh Token
重要 Angular >4.3 & <5.2.3
我使用 HttpClient 并创建了这个拦截器来添加 jwt 令牌。 Everyting工作完美,但我有一个不好的做法。我在 HttpClient 拦截器中使用 Http。如果我改变
private http: Http,
到
private http: HttpClient
我收到这个循环错误
Cannot instantiate cyclic dependency! InjectionToken_HTTP_INTERCEPTORS ("[ERROR ->]")
有什么想法可以让它发挥作用吗?
import {Injectable} from "@angular/core";
import {HttpEvent, HttpHandler, HttpInterceptor} from "@angular/common/http";
import {HttpRequest} from "@angular/common/http";
import {Observable} from "rxjs/Observable";
import {Http} from "@angular/http";
import {SiteService} from "../services/site.service";
import {Router} from "@angular/router";
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(
private http: Http,
private router: Router,
private siteService: SiteService
) {}
refreshToken() {
return this.http.get(this.siteService.apiDomain() + '/api/token?token=' + localStorage.getItem('JWToken'), {})
.map((response: any) => {
let data = response.json();
return {
token: data.token,
permissions: data.permissions,
user: data.user,
};
})
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const clonedRequest = req.clone({
headers: req.headers.set('Authorization', 'Bearer ' + localStorage.getItem('JWToken'))
});
return next.handle(clonedRequest).catch((res) => {
if (res.status === 401 || res.status === 403) {
return this.refreshToken().flatMap((data) => {
if (data.token !== '') {
localStorage.setItem('currentUser', JSON.stringify(data.user));
localStorage.setItem('currentUserPermissions', JSON.stringify(data.permissions));
localStorage.setItem('JWToken', data.token);
} else {
localStorage.removeItem('currentUser');
localStorage.removeItem('currentUserPermissions');
localStorage.removeItem('JWToken');
this.router.navigate(['./auth/login']);
return Observable.throw(res);
}
const clonedRequestRepeat = req.clone({
headers: req.headers.set('Authorization', 'Bearer ' + localStorage.getItem('JWToken'))
});
return next.handle(clonedRequestRepeat);
})
} else {
return Observable.throw(res);
}
});
}
}
对于那些将在他们的项目中使用此拦截器但与当前问题无关的人来说,另一件重要的事情是将 headers 设置为至少几秒钟的刷新令牌响应。
->header('Cache-Control', 'public, max-age=45')
->header('Expires', date('D, d M Y H:i:s ', time() + 45).'GMT');
我决定不在构造函数中设置 authService,而是进入拦截函数。
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// Get the auth header from the service.
const auth = this.inj.get(AuthenticationService);
const authToken = auth.getAuthorizationToken();
...
}
你必须先将 Injector 添加到你的构造函数中
constructor(
...
private inj: Injector
) {}
您也可以尝试一些技巧来实例化该服务,例如:
constructor(private injector: Injector) {
setTimeout(() => {
this.loginService = this.injector.get(LoginService);
})
}
这样你就不会得到超出最大调用堆栈的错误。
重要 Angular >4.3 & <5.2.3
我使用 HttpClient 并创建了这个拦截器来添加 jwt 令牌。 Everyting工作完美,但我有一个不好的做法。我在 HttpClient 拦截器中使用 Http。如果我改变
private http: Http,
到
private http: HttpClient
我收到这个循环错误
Cannot instantiate cyclic dependency! InjectionToken_HTTP_INTERCEPTORS ("[ERROR ->]")
有什么想法可以让它发挥作用吗?
import {Injectable} from "@angular/core";
import {HttpEvent, HttpHandler, HttpInterceptor} from "@angular/common/http";
import {HttpRequest} from "@angular/common/http";
import {Observable} from "rxjs/Observable";
import {Http} from "@angular/http";
import {SiteService} from "../services/site.service";
import {Router} from "@angular/router";
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(
private http: Http,
private router: Router,
private siteService: SiteService
) {}
refreshToken() {
return this.http.get(this.siteService.apiDomain() + '/api/token?token=' + localStorage.getItem('JWToken'), {})
.map((response: any) => {
let data = response.json();
return {
token: data.token,
permissions: data.permissions,
user: data.user,
};
})
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const clonedRequest = req.clone({
headers: req.headers.set('Authorization', 'Bearer ' + localStorage.getItem('JWToken'))
});
return next.handle(clonedRequest).catch((res) => {
if (res.status === 401 || res.status === 403) {
return this.refreshToken().flatMap((data) => {
if (data.token !== '') {
localStorage.setItem('currentUser', JSON.stringify(data.user));
localStorage.setItem('currentUserPermissions', JSON.stringify(data.permissions));
localStorage.setItem('JWToken', data.token);
} else {
localStorage.removeItem('currentUser');
localStorage.removeItem('currentUserPermissions');
localStorage.removeItem('JWToken');
this.router.navigate(['./auth/login']);
return Observable.throw(res);
}
const clonedRequestRepeat = req.clone({
headers: req.headers.set('Authorization', 'Bearer ' + localStorage.getItem('JWToken'))
});
return next.handle(clonedRequestRepeat);
})
} else {
return Observable.throw(res);
}
});
}
}
对于那些将在他们的项目中使用此拦截器但与当前问题无关的人来说,另一件重要的事情是将 headers 设置为至少几秒钟的刷新令牌响应。
->header('Cache-Control', 'public, max-age=45')
->header('Expires', date('D, d M Y H:i:s ', time() + 45).'GMT');
我决定不在构造函数中设置 authService,而是进入拦截函数。
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// Get the auth header from the service.
const auth = this.inj.get(AuthenticationService);
const authToken = auth.getAuthorizationToken();
...
}
你必须先将 Injector 添加到你的构造函数中
constructor(
...
private inj: Injector
) {}
您也可以尝试一些技巧来实例化该服务,例如:
constructor(private injector: Injector) {
setTimeout(() => {
this.loginService = this.injector.get(LoginService);
})
}
这样你就不会得到超出最大调用堆栈的错误。