如何使用角度2中的自定义http刷新访问令牌?

时间:2017-03-07 10:08:16

标签: javascript angular typescript oauth-2.0 refresh-token

我在我的应用程序中使用基于令牌的身份验证。我的后端是使用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中提到的相同的方法。任何帮助都会很棒!

3 个答案:

答案 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())吗?