簡體   English   中英

Angular2:帶標記頭的oauth2

[英]Angular2: oauth2 with token headers

我是angular2的新手。 在1. *攔截器的一切都很好,只需添加它們:你的標頭到處都有,你可以處理你的請求,當令牌變得無效時......

angular2我正在使用RxJs 所以我得到了我的令牌:

  getToken(login: string, pwd: string): Observable<boolean> {

    let bodyParams = {
      grant_type: 'password',
      client_id: 'admin',
      scope: AppConst.CLIENT_SCOPE,
      username: login,
      password: pwd
    };

    let params = new URLSearchParams();
    for (let key in bodyParams) {
      params.set(key, bodyParams[key])
    }

    let headers = new Headers({'Content-Type': 'application/x-www-form-urlencoded'});
    let options = new RequestOptions({headers: headers});

    return this.http.post(AppConst.IDENTITY_BASE_URI + '/connect/token', params.toString(), options)
      .map((response: Response) => {
        let data = response.json();

        if (data) {
          this.data = data;
          localStorage.setItem('auth', JSON.stringify({
            access_token: data.access_token,
            refresh_token: data.refresh_token
          }));
          return true;
        } else {
          return false;
        }
      });
  }

然后我如何在每個請求中使用此令牌? 我不想在每個請求中設置.header 這是一個不好的做法。

然后:例如,當我做任何請求,並獲得401 error時,我如何攔截並獲得新的令牌,然后恢復所有請求,就像它在angular 1

我試圖從這里jwt使用JWT ,但是它不符合我的要求,順便說一下第一個角度我正在使用Restangular - 並且一切都很好(也有手冊上的令牌: https//github.com/mgonto/restangular #seterrorinterceptor

您可以擴展默認的http服務並使用擴展版本,也可以創建一個獲取某些參數的方法(如果需要)並返回RequestOptions對象以傳遞默認的http服務。

選項1

您可以創建服務:

@Injectable()
export class HttpUtils {
  constructor(private _cookieService: CookieService) { }

  public optionsWithAuth(method: RequestMethod, searchParams?: URLSearchParams): RequestOptionsArgs {
    let headers = new Headers();
    let token = 'fancyToken';
    if (token) {
      headers.append('Auth', token);
    }
    return this.options(method, searchParams, headers);
  }

  public options(method: RequestMethod, searchParams?: URLSearchParams, header?: Headers): RequestOptionsArgs {
    let headers = header || new Headers();
    if (!headers.has('Content-Type')) {
      headers.append('Content-Type', 'application/json');
    }
    let options = new RequestOptions({headers: headers});
    if (method === RequestMethod.Get || method === RequestMethod.Delete) {
      options.body = '';
    }
    if (searchParams) {
      options.params = searchParams;
    }
    return options;
  }

  public handleError(error: Response) {
    return (res: Response) => {
      if (res.status === 401) {
        // do something
      }
      return Observable.throw(res);
    };
  }
}

用法示例:

this._http
  .get('/api/customers', this._httpUtils.optionsWithAuth(RequestMethod.Get))
  .map(res => <Customer[]>res.json())
  .catch(err => this._httpUtils.handleError(err));

此示例使用cookie來存儲和訪問令牌。 您也可以使用參數。


選項2

第二個選項是擴展http服務,例如:

import { Injectable } from '@angular/core';
import { Http, XHRBackend, RequestOptions, Request, RequestOptionsArgs, Response, Headers } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';

@Injectable()
export class MyHttp extends Http {

  constructor (backend: XHRBackend, options: RequestOptions) {
    let token = 'fancyToken';
    options.headers.set('Auth', token);
    super(backend, options);
  }

  request(url: string|Request, options?: RequestOptionsArgs): Observable<Response> {
    let token = 'fancyToken';
    if (typeof url === 'string') {
      if (!options) {
        options = {headers: new Headers()};
      }
      options.headers.append('Auth', token);
    } else {
      url.headers.append('Auth', token);
    }
    return super.request(url, options).catch(this.handleError(this));
  }

  private handleError (self: MyHttp) {
    return (res: Response) => {
      if (res.status === 401) {
        // do something
      }
      return Observable.throw(res);
    };
  }
}

在你的@NgModule

@NgModule({
  // other stuff ...
  providers: [
    {
      provide: MyHttp,
      useFactory: (backend: XHRBackend, options: RequestOptions) => {
        return new MyHttp(backend, options);
      },
      deps: [XHRBackend, RequestOptions]
    }
  ]
  // a little bit more other stuff ...
})

用法:

@Injectable()
class CustomerService {

  constructor(private _http: MyHttp) {
  }

  query(): Observable<Customer[]> {
    return this._http
      .get('/api/customers')
      .map(res => <Customer[]>res.json())
      .catch(err => console.log('error', err));
  }
}

額外:

如果要使用刷新令牌獲取新令牌,可以執行以下操作:

private handleError (self: MyHttp, url?: string|Request, options?: RequestOptionsArgs) {
  return (res: Response) => {
    if (res.status === 401 || res.status === 403) {
      let refreshToken:string = 'fancyRefreshToken';
      let body:any = JSON.stringify({refreshToken: refreshToken});
      return super.post('/api/token/refresh', body)
        .map(res => {
          // set new token
        }) 
        .catch(err => Observable.throw(err))
        .subscribe(res => this.request(url, options), err => Observable.throw(err));
    }
    return Observable.throw(res);
  };
}

說實話,我沒有測試過這個,但它至少可以為你提供一個起點。

我們通過擴展AuthHttp解決了這個問題。 我們在AuthHttp上添加了一個方法a來動態設置一個新的頭(X-RoleId是一個自定義頭)

declare module 'angular2-jwt' {
  interface AuthHttp {
    setRoleId(config: {});
  }
}

AuthHttp.prototype.setRoleId = function (roleId) {
  let jsThis = <any>(this);
  jsThis.config.globalHeaders = [
          {'Content-Type': 'application/json'}, 
          {'X-RoleId': roleId}
          ];
};

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM