how to refresh the access token using custom http in angular 2?

后端 未结 3 769
孤独总比滥情好
孤独总比滥情好 2021-02-06 18:50

I am using token based authentication in my application. My backend is developed using restful service(spring).The backend code is very well generating the required the access t

相关标签:
3条回答
  • 2021-02-06 19:43

    For those who get to this page and don't understand a thing from it.

    The easy to understand:

    Create your refresh token method: //retrieve the refresh token somehow

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

    Than in your http request (mine uses the angular-jwt authHttp instead of 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));
    
      }
    

    Do not forget to import what you need like:

    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';
    

    Do not subscribe in your refresh token method. If you do you will see a big error in the flatmap of the service call method.

    0 讨论(0)
  • 2021-02-06 19:44

    thanks for replying @dragonfly, this worked for me

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

    Can you tell how are you updating the token(this.authenticationService.updateToken())?

    0 讨论(0)
  • 2021-02-06 19:53

    This is what worked for me:

     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() implementation should depend on authorization provider/authorization mechanism you use. In my case it is OAuth Athorization Server, so implementation basically sends post request with refresh token in the body to configured token url and returns updated access and refresh tokens. tokenEndPointUrl is configured by OAuth and issues access and refresh tokens (depending on grant_type sent). Because i need to refresh token i set grant_type to refresh_token. Code looks similar to:

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

    Hope it helps

    0 讨论(0)
提交回复
热议问题