如何使用新标头处理克隆请求?
我试图在新的拦截器中执行克隆请求,并在第一个请求失败后生成新令牌!
这是我试过的:
refreshSessionToken() {
return this.http.post('/connect', {})
.map(res => {
const token = res.json();
localStorage.setItem('token', token);
return token;
});
}
// Get the headers
const headers = getAuthenticationHeaders();
const reqMain = req.clone({headers: headers});
return next.handle(reqMain).catch(err => {
this.refreshSessionToken()
.subscribe(token => {
const t = token.token_id;
const clonedReq = req.clone({headers: req.headers.set('access-token', t)});
return next.handle(clonedReq);
});
})
获取 clonedReq 的日志我可以看到令牌已刷新,但订阅中的请求(clonedReq)未执行,为什么?!
我尝试了其他关于如何刷新JWT的方法,但在我的情况下似乎不起作用,有关如何处理它的任何帮助?
谢谢!
我期望什么是我的结果?
类似问题:
答案 0 :(得分:3)
以下通用方法可用于拦截以及添加/删除呼叫和响应的其他信息。
好的,这里是完整的代码。
<强> InterceptedHttp.ts 强>
import { Injectable } from "@angular/core";
import { RequestOptions, Http, Headers, Response, RequestMethod, URLSearchParams } from "@angular/http";
import { Observable, Observer } from 'rxjs/Rx';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import "rxjs/add/operator/mergeMap";
@Injectable()
export class InterceptedHttp {
constructor(private http: Http) { }
getRequestOption(method: RequestMethod | string, data?: any, params?: any): RequestOptions {
let options = new RequestOptions();
options.headers = new Headers();
//options.headers.append('Content-Type', 'application/json');
options.method = method;
let token: string = localStorage.getItem('token');
//if (token) options.headers.append('Authorization', 'Bearer ' + token);
if (data) options.body = data;
if (params) {
options.search = new URLSearchParams();
let keys: string[] = Object.keys(params);
keys.forEach((key, index) => {
options.search.set(key, params[key]);
});
}
return options;
}
refreshSessionToken(): Observable<string> {
//Put some user identification data
let userData: any = {id: 'abc'};
return this.http.post('/refreshToken', userData)
.map(res => {
let token = res.json();
localStorage.setItem('token', token);
return token;
});
}
getApiResponse<T>(url: string, method: RequestMethod | string, data?: Object): Observable<T> {
let op1: RequestOptions = this.getRequestOption(method, data);
return this.http.request(url, op1)
.catch((err) => {
// UnAuthorised, 401
if (err.status == 401) {
return this.refreshSessionToken().flatMap(t => {
let op2 = this.getRequestOption(method, data);
return this.http.request(url, op2);
});
}
throw err;
})
.map((response: Response) => {
let ret: T = response.json();
return ret;
});
}
get<T>(url: string): Observable<T> {
return this.getApiResponse<T>(url, RequestMethod.Get);
}
post<T, R>(url: string, body: T): Observable<R> {
return this.getApiResponse<R>(url, RequestMethod.Post, body);
}
put<T, R>(url: string, body: T): Observable<R> {
return this.getApiResponse<R>(url, RequestMethod.Put, body);
}
delete<T>(url: string): Observable<T> {
return this.getApiResponse<T>(url, RequestMethod.Delete);
}
}
<强> DataService.ts 强>
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { User } from './User';
import { InterceptedHttp } from './http.interceptor';
@Injectable()
export class DataService {
constructor(private apiHandler: InterceptedHttp) { }
getAll(): Observable<User[]> {
return this.apiHandler.get<User[]>('http://mocker.egen.io/users');
}
}
<强> User.ts 强>
export class User {
id?: number;
firstName?: string;
lastName?: string;
}
<强> AppComponent.ts 强>
import { Component } from '@angular/core';
import { DataService } from './user-data.service';
import { User } from './User';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app works!';
users: User[];
constructor(dataService: DataService){
dataService.getAll().subscribe((u) => {
this.users = u;
});
}
}
<强> app.component.html 强>
<h1>
<table>
<tr *ngFor="let item of users; let i = index">
<td> {{item.firstName}} </td>
</tr>
</table>
</h1>
答案 1 :(得分:1)
这是我使用最新版本的Angular(7.0.0)和rxjs(6.3.3)的解决方案。希望对您有所帮助。
export class SessionRecoveryInterceptor implements HttpInterceptor {
constructor(
private readonly store: StoreService,
private readonly sessionService: AuthService
) {}
private _refreshSubject: Subject<any> = new Subject<any>();
private _ifTokenExpired() {
this._refreshSubject.subscribe({
complete: () => {
this._refreshSubject = new Subject<any>();
}
});
if (this._refreshSubject.observers.length === 1) {
// Hit refresh-token API passing the refresh token stored into the request
// to get new access token and refresh token pair
this.sessionService.refreshToken().subscribe(this._refreshSubject);
}
return this._refreshSubject;
}
private _checkTokenExpiryErr(error: HttpErrorResponse): boolean {
return (
error.status &&
error.status === 401 &&
error.error &&
error.error.message === "TokenExpired"
);
}
intercept(
req: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
if (req.url.endsWith("/logout") || req.url.endsWith("/token-refresh")) {
return next.handle(req);
} else {
return next.handle(req).pipe(
catchError((error, caught) => {
if (error instanceof HttpErrorResponse) {
if (this._checkTokenExpiryErr(error)) {
return this._ifTokenExpired().pipe(
switchMap(() => {
return next.handle(this.updateHeader(req));
})
);
} else {
return throwError(error);
}
}
return caught;
})
);
}
}
updateHeader(req) {
const authToken = this.store.getAccessToken();
req = req.clone({
headers: req.headers.set("Authorization", `Bearer ${authToken}`)
});
return req;
}
}
答案 2 :(得分:0)
我回答了类似的问题here
您无法将克隆的请求传递到下一个处理程序。相反,使用HttpClient重新尝试克隆的请求。
this.http.request(clonedReq).subscribe(......);