Ionic 3 + HttpClientModule和存储中的令牌

时间:2018-01-04 14:59:32

标签: ionic-framework angular-http-interceptors

我已经构建了一个拦截器,用于向PHP后端发出HTTP请求。 这个后端为应用程序提供了一个JWT令牌,我将其保存在Ionic Storage中。 但我希望从Storage获取该令牌并将其作为标头添加到HTTP请求中。

下面是我的拦截器和硬编码令牌。 这有效,我从后端得到回复。

请参阅此帖子的更新@底部

HTTP-interceptor.ts

import { HttpInterceptor, HttpRequest } from '@angular/common/http/';
import {HttpEvent, HttpHandler} from '@angular/common/http';
import { AuthProvider } from "../providers/auth/auth";
import {Injectable} from "@angular/core";
import {Observable} from "rxjs/Observable";
import {Storage} from "@ionic/storage";

@Injectable()
export class TokenInterceptor implements HttpInterceptor {

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        const changedReq = req.clone({headers: req.headers.set('Authorization', 'Bearer MY TOKEN')});
        return next.handle(changedReq);
    }

}

但是如何将存储中的令牌放入标头中。 我搜索了很多,大多数教程/示例来自较旧的HTTP模块。如果有人有想法或有up2date示例?

更新

代码下面的Oke发送令牌

intercept(req: HttpRequest<any>, next: HttpHandler) : Observable<HttpEvent<any>>{
        return fromPromise(this.Auth.getToken())
            .switchMap(token => {
                const changedReq = req.clone({headers: req.headers.set('Authorization', 'Bearer ' + token )});

                return next.handle(changedReq);
            });
    }

有1个例外,即我第一次访问该页面:)

3 个答案:

答案 0 :(得分:4)

您可以将JWT令牌保存在例如 localStorage

 localStorage.setItem('myToken', res.token);

然后使用

访问它
localStorage.getItem('myToken');

在你的情况下是这样的:

import { HttpInterceptor, HttpRequest } from '@angular/common/http/';
import {HttpEvent, HttpHandler} from '@angular/common/http';
import { AuthProvider } from "../providers/auth/auth";
import {Injectable} from "@angular/core";
import {Observable} from "rxjs/Observable";
import {Storage} from "@ionic/storage";

@Injectable()
export class TokenInterceptor implements HttpInterceptor {

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        const changedReq = req.clone({headers: req.headers.set('Authorization', localStorage.getItem('myToken'))});
        return next.handle(changedReq);
    }

}

如果您想使用Ionic Storage

import { HttpInterceptor, HttpRequest } from '@angular/common/http/';
    import {HttpEvent, HttpHandler} from '@angular/common/http';
    import { AuthProvider } from "../providers/auth/auth";
    import {Injectable} from "@angular/core";
    import {Observable} from "rxjs/Observable";
    import {Storage} from "@ionic/storage";

   @Injectable()
    export class TokenInterceptor implements HttpInterceptor {

    constructor(public _storage: Storage) {
         _storage.get('myToken').then((val) => {
         console.log('Your age is', val);
         });
    }

       intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
            const changedReq = req.clone({headers: req.headers.set('Authorization', this.val)});
            return next.handle(changedReq);
        }

    }

答案 1 :(得分:3)

在拦截器中缓存令牌是一个坏主意,因为如果令牌发生更改,拦截器将不会意识到这些更改。

// Don't do this.
token: string;
constructor(private storage: Storage) {
  this.storage.get('token').then((res) => {
     this.token = res;
  })
}

如果您想同时使用Ionic Storage和拦截器,可以像这样使用Observable.flatMap来实现。

app.module.ts

providers: [
    { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true},
    SecurityStorageService
]

AuthInterceptor.ts

@Injectable()
export class AuthInterceptor implements HttpInterceptor {

constructor(
  private securityStorageService: SecurityStorageService
) {}

 intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    // This method gets a little tricky because the security token is behind a   
    // promise (which we convert to an observable). So we need to concat the 
    // observables.
    //  1. Get the token then use .map to return a request with the token populated in the header.
    //  2. Use .flatMap to concat the tokenObservable and next (httpHandler)
    //  3. .do will execute when the request returns
    const tokenObservable = this.securityStorageService.getSecurityTokenAsObservable().map(token => {
      return request = request.clone({
        setHeaders: {
          Authorization: `Bearer ${token}`
        }
      });
    });

    return tokenObservable.flatMap((req) => {
      return next.handle(req).do((event: HttpEvent<any>) => {
        if (event instanceof HttpResponse) {
          // do stuff to the response here
        }
      }, (err: any) => {
        if (err instanceof HttpErrorResponse) {
          if (err.status === 401) {
            // not authorized error .. do something
          }
        }
      });
    })
  }

security-storage-service.ts

从技术上讲,您不需要此服务,但拦截器中不应包含离子存储逻辑。

@Injectable()
export class SecurityStorageService {

  constructor(private storage: Storage) {

  }

  getSecurityToken() {
    return this.storage.get(StorageKeys.SecurityToken)
      .then(
      data => { return data },
      error => console.error(error)
    );
  }
  getSecurityTokenAsObservable() {
    return Observable.fromPromise(this.getSecurityToken());
  }
}

storage-keys.ts

export class StorageKeys {  
  public static readonly SecurityToken: string = "SecurityToken";
}

答案 2 :(得分:3)

对于像我这样遇到并且正在使用 rxjs> = 5.5.0 的任何人,您都可以这样做:

auth-interceptor.ts

@Injectable()
export class AuthInterceptor implements HttpInterceptor {

constructor(private authService: AuthService) { }

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

    return from(this.authService.getToken()).pipe(mergeMap((token) => {
        const changedReq = req.clone({
            setHeaders: {
                Authorization: `Bearer ${token}`
            }
        });

        return next.handle(changedReq);
    }));
}

auth-service.ts

public async getToken() {
    return await this.storage.get('ACCESS_TOKEN');
}