Angular2:带标记头的oauth2

bra*_*r19 6 javascript typescript angular

我是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;
        }
      });
  }
Run Code Online (Sandbox Code Playgroud)

然后我如何在每个请求中使用此令牌?我不想.header在每个请求中设置.这是一个不好的做法.

然后:例如,当我做任何请求,并获得401-error时,我如何拦截,获取新令牌,然后恢复所有请求,就像它在angular 1

我试图JWT从这里使用jwt,但它不符合我的要求,顺便说一下我使用的第一个角度Restangular- 一切都很好(也有手册上的令牌:https://github.com/mgonto/restangular#seterrorinterceptor)

s.a*_*lem 5

您可以扩展默认的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);
    };
  }
}
Run Code Online (Sandbox Code Playgroud)

用法示例:

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

此示例使用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);
    };
  }
}
Run Code Online (Sandbox Code Playgroud)

在你的@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 ...
})
Run Code Online (Sandbox Code Playgroud)

用法:

@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));
  }
}
Run Code Online (Sandbox Code Playgroud)

额外:

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

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);
  };
}
Run Code Online (Sandbox Code Playgroud)

说实话,我没有测试过这个,但它至少可以为你提供一个起点.