目前我遇到了逻辑实现的问题。
我想做下一件事:
如果有任何签名(已签名 - 表示已提供JWT令牌,对于经过身份验证的用户)请求已向API后端发出,则API后端可能会返回401 JWT Token Expired。在这种情况下,我想再次调用刷新JWT令牌,然后(如果成功) - 再次发出原始请求。如果失败 - 重定向到登录页面。
此实施的当前问题是:
1)refreshToken()在ApiService中,但我认为它应该在AuthService中,因为它与身份验证有关。但是如果我移动方法 - 那么我必须在ApiService中注入AuthService(它扩展了ApiService),这里出现了死循环问题+我不知道如何在构造函数中为AuthService传递这个参数,来制作.super(args) )打电话。
2)目前我的代码无效,因为这部分:
this.refreshToken().toPromise().then(() => {
if (request.data) {
console.log('POST');
return this[request.method](request.endpoint, request.data);
} else {
console.log('GET');
return this[request.method](request.endpoint);
}
});
由于refreshToken是异步的,我无法返回(实际调用)原始方法。我应该怎么处理这个?
我的代码示例如下:
的DataService
import { Injectable } from '@angular/core';
import { Http, RequestOptions } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import { Headers } from '@angular/http';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
import 'rxjs/add/observable/throw';
import { NotFoundError } from '../errors/response-errors/not-found-error';
import { BadRequest } from '../errors/response-errors/bad-request';
import { AppError } from '../errors/app-error';
import { Unauthorized } from '../errors/response-errors/unauthorized';
@Injectable()
export class DataService {
protected lastRequest: any;
constructor(private url: string, private http: Http) {}
get(endpoint) {
console.log('called get: ' + endpoint);
console.log('THIS:', this);
this.lastRequest = {
'method': 'get',
'endpoint': endpoint,
};
return this.http
.get(this.url + endpoint, this.options)
.map((response) => {
const r = response.json();
console.log('Response (get):');
console.log(r);
return r;
// return response.json();
})
.catch(error => this.handleError(error));
}
post(endpoint, data) {
console.log('called post: ' + endpoint);
this.lastRequest = {
'method': 'post',
'endpoint': endpoint,
'data': data
};
return this.http
.post(this.url + endpoint, data, this.options)
.map((response) => {
const r = response.json();
console.log('Response:');
console.log(r);
return r;
// return response.json();
})
.catch(error => this.handleError(error));
}
get options() {
const token = localStorage.getItem('token');
if (token) {
const headers = new Headers();
headers.append('Authorization', 'Bearer ' + token);
return new RequestOptions({
headers: headers
});
}
return null;
}
protected handleError(error: Response): any {
if (error.status === 400) {
return Observable.throw(new BadRequest(error.json()));
}
if (error.status === 401) {
return Observable.throw(new Unauthorized());
}
if (error.status === 404) {
return Observable.throw(new NotFoundError());
}
return Observable.throw(new AppError(error.json()));
}
}
ApiService
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { DataService } from './data.service';
import { Observable } from 'rxjs/Observable';
import { Unauthorized } from '../errors/response-errors/unauthorized';
import { AuthService } from './auth.service';
@Injectable()
export class ApiService extends DataService {
constructor(http: Http) {
super('https://my-api-endpoint', http);
}
refreshToken() {
console.log('refreshToken clalled');
const refreshToken = localStorage.getItem('refresh_token');
console.log('using refresh token:', refreshToken);
if (refreshToken) {
return this.post('/renew-access-token', {
refresh_token: refreshToken
})
.map(response => {
console.log('got refreshToken response:');
console.log(response);
localStorage.setItem('token', response.token);
localStorage.setItem('refresh_token', response.refresh_token);
});
}
}
protected handleError(error: Response) {
if (error.status === 401) {
const res: any = error.json();
if (res && res.message === 'Expired JWT Token') {
const request = this.lastRequest;
console.log('last request:', request);
this.refreshToken().toPromise().then(() => {
if (request.data) {
console.log('POST');
return this[request.method](request.endpoint, request.data);
} else {
console.log('GET');
return this[request.method](request.endpoint);
}
});
}
console.log('NO');
return Observable.throw(new Unauthorized());
}
return super.handleError(error);
}
}
TendersService
import { Injectable } from '@angular/core';
import { ApiService } from './api.service';
import { Http, URLSearchParams } from '@angular/http';
@Injectable()
export class TendersService extends ApiService {
constructor(http: Http) {
super(http);
}
getTenders(dateFrom, dateTo, status = 'actual', limit = 5, offset = 0) {
const params = new URLSearchParams();
params.set('date_from', dateFrom);
params.set('date_to', dateTo);
params.set('status', status);
params.set('limit', limit.toString());
params.set('offset', offset.toString());
return this.get('/tenders?' + params.toString());
}
}
AuthService
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { ApiService } from './api.service';
import 'rxjs/add/operator/map';
import { tokenNotExpired, JwtHelper } from 'angular2-jwt';
@Injectable()
export class AuthService extends ApiService {
constructor(http: Http) {
super(http);
}
login(credentials) {
return this.post('/login', credentials)
.map(response => {
localStorage.setItem('token', response.token);
localStorage.setItem('refresh_token', response.refresh_token);
});
}
logout() {
const refreshToken = localStorage.getItem('refresh_token');
if (refreshToken) {
this.post('/logout', {
refresh_token: refreshToken
}).toPromise();
}
localStorage.removeItem('token');
localStorage.removeItem('refresh_token');
}
isLoggedIn() {
return !!localStorage.getItem('refresh_token');
}
}
答案 0 :(得分:0)
我认为你可以考虑在服务继承上使用依赖注入。移动方法,如" refreshToken"到AuthService是个好主意,但你也应该移动" handleError" AuthService的方法,因为该方法也应该只处理身份验证错误,例如更新令牌或注销用户。所以在那之后你不再需要继承你的ApiService了,我根本不太了解它的用途。
之后,在您的DataService中,您只需注入您的AuthService(而不是继承),并通过向请求添加身份验证标头来修改发送请求。从我的角度来看,我认为最好将AuthService与DataService分开。