2017-03-07 30 views
2

我在我的应用程序中使用基于令牌的身份验证。我的后端使用RESTful服务(春季)。该后端代码是很好的生成与时间表需要的访问令牌和刷新令牌的发展,所以我overidden的HTTP类如下:如何使用角2中的自定义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); 
       } 
      }); } } 

我被陷在refresh()方法刷新令牌,因为我得到循环依赖性错误,所以我尝试在另一个模块中使用刷新服务,但没有运气。我正在使用与此Handling refresh tokens using rxjs中提到的相同的方法任何帮助都会很棒!

回答

3

这是对我工作:

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); 
      } 
     }) 
} 

UPDATE:authenticationService.updateToken()实施应该取决于授权提供/使用授权机制。在我的情况下,它是OAuth Athorization Server,因此实现基本上将带有刷新令牌的发布请求发送到配置的令牌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

但401并不一定意味着无效标记,该标记是有效的,但不是针对该请求,这意味着401将继续激活,并且您将进入循环以重新创建刷新标记...我对么? – Ayyash

+0

或者,也许403是我的意思?所以令人困惑... – Ayyash

+0

我想这是身份验证和授权在这里混淆。 401 UNAUTHORIZED - 请求尚未应用,因为它缺少目标资源的有效认证凭证。 403 FORBIDDEN - 服务器了解请求但拒绝授权。所以如果你从服务器获得401 - 你的凭证是陈旧的。如果您收到了403服务器的身份验证,但由于缺乏权限而无法授权您访问。因此,403更关于您在系统中的权限而不是关于您的令牌。在拥有权限之前,您永远无法使用令牌访问权限。 – Dragonfly

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())?

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请求(我使用的角度,智威汤逊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'; 

请勿在您的刷新标记方法中订阅。如果你这样做,你会在服务调用方法的平面图中看到一个很大的错误。

+0

嗨,如果多个https请求在近距离发送或平面地图会阻止这种请求,这是否会导致多个刷新请求?我问的原因是因为我有一个类似的设置,但我使用的是订阅而不是flatmap。虽然刷新成功,但用户体验很糟糕,因为它最终会重定向到登录,然后回来。我想采用你的解决方案。谢谢 –

相关问题