我在我的应用程序中使用基于令牌的身份验证。我的后端是使用restful service(spring)开发的。后端代码很好地生成了所需的访问令牌和刷新时间轴的令牌,所以我已经覆盖了以下的http类:
export class customHttp extends Http {
headers: Headers = new Headers({ 'Something': 'Something' });
options1: RequestOptions = new RequestOptions({ headers: this.headers });
private refreshTokenUrl = AppSettings.REFRESH_TOKEN_URL;
constructor(backend: ConnectionBackend,
defaultOptions: RequestOptions,private refresh:OauthTokenService) {
super(backend, defaultOptions);
}
request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
console.log("custom http ");
return super.request(url, options)
.catch((err) => {
if (err.status === 401) {
console.log(" custome http 401 ");
// refresh the token
this.refresh.refresh().subscribe((tokenObj)=>{
console.log("tokenobj ");
})
} else {
console.log("err " + err);
}
}); } }
由于我遇到循环依赖性错误,因此我在刷新()方法时遇到刷新问题,所以我试图在另一个模块中使用刷新服务,但没有运气。我正在使用与此Handling refresh tokens using rxjs中提到的相同的方法。任何帮助都会很棒!
答案 0 :(得分:5)
这对我有用:
request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
//adding access token to each http request before calling super(..,..)
let token = this.authenticationService.token;
if (typeof url === 'string') {
if (!options) {
options = { headers: new Headers() };
}
options.headers.set('Authorization', `Bearer ${token}`);
}
else {
url.headers.set('Authorization', `Bearer ${token}`);
}
return super.request(url, options)
.catch((error) => {
//if got authorization error - try to update access token
if (error.status = 401) {
return this.authenticationService.updateToken()
.flatMap((result: boolean) => {
//if got new access token - retry request
if (result) {
return this.request(url, options);
}
//otherwise - throw error
else {
return Observable.throw(new Error('Can\'t refresh the token'));
}
})
}
else {
Observable.throw(error);
}
})
}
更新:authenticationService.updateToken()实现应该依赖于您使用的授权提供程序/授权机制。在我的例子中它是OAuth Athorization Server,因此实现基本上将带有刷新令牌的post请求发送到配置的令牌url并返回更新的访问和刷新令牌。 tokenEndPointUrl由OAuth配置并发出访问和刷新令牌(取决于发送的grant_type)。因为我需要刷新令牌我将grant_type设置为refresh_token。代码类似于:
updateToken(): Observable<boolean> {
let body: string = 'refresh_token=' + this.refreshToken + '&grant_type=refresh_token';
return this.http.post(tokenEndPointUrl, body, this.options)
.map((response: Response) => {
var returnedBody: any = response.json();
if (typeof returnedBody.access_token !== 'undefined'){
localStorage.setItem(this.tokenKey, returnedBody.access_token);
localStorage.setItem(this.refreshTokenKey, returnedBody.refresh_token);
return true;
}
else {
return false;
}
})
}
希望有所帮助
答案 1 :(得分:1)
对于那些访问此页面并且不了解其中的内容的人。
易于理解:
创建刷新令牌方法: //以某种方式检索刷新令牌
refreshToken(){
let refreshToken = sessionStorage.getItem('refresh_token');
let body = 'grant_type=refresh_token&refresh_token=' + refreshToken;
var headers = new Headers();
headers.append('Content-Type', 'application/x-www-form-urlencoded');
headers.append('Authorization','Basic ' + btoa('something:something'));
return this.http.post('your auth url',body,{headers: headers})
}
比你的http请求(我使用angular-jwt authHttp而不是http)
testService(){
this.authHttp.get('your secured service url')
.map(res => {
return res;
})
.catch(error=> {
if (error.status === 401) {
return this.refreshToken().flatMap((newToken) => {
let newAccessToken = newToken.json();
sessionStorage.setItem('id_token', newAccessToken['access_token']);
sessionStorage.setItem('refresh_token', newAccessToken['refresh_token']);
return this.authHttp.request('your secured service url');
})
} else {
return Observable.throw(error);
}
})
.subscribe(res => console.log(res));
}
不要忘记导入您需要的内容:
import { AuthHttp } from 'angular2-jwt';
import { Observable } from "rxjs/Observable";
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';
请勿在刷新令牌方法中订阅。如果这样,您将在服务调用方法的平面图中看到一个很大的错误。
答案 2 :(得分:0)
感谢回复@dragonfly,这对我有用
post(url: string, body: any, options?: RequestOptionsArgs): Observable<Response> {
//check if the token is expired then set the latest token
if (this.isTokenExpired) {
options.headers.set('Authorization', 'Bearer ' + localStorage.getItem("accessToken"));
}
return super.post(url, body, options)
.catch((err) => {
//if authentication error
if (err.status === 401) {
this.isTokenExpired = true;
options.headers.set('Authorization', 'Bearer ' + localStorage.getItem("accessToken"));
//refresh the token
let refreshUrl = this.refreshTokenUrl;
//pass the refresh token
refreshUrl = refreshUrl.replace(':refreshToken', localStorage.getItem("refreshToken"));
//rest the access token
return super.get(refreshUrl).mergeMap((tokenObj) => {
localStorage.setItem("accessToken", tokenObj.json().value);
// reset the headers
options.headers.set('Authorization', 'Bearer ' + localStorage.getItem("accessToken"));
//retry the request with the new access token
return this.post(url, body, options)
})
.catch((refreshErr) => {
if (refreshErr.status == 400) {
console.log("refesh err");
window.location.href = 'request=logout';
}
return Observable.throw(refreshErr);
})
} else {
return err;
}
})
}
你能告诉你如何更新令牌(this.authenticationService.updateToken())吗?