首页 > 解决方案 > 刷新 JWT 令牌 - Angular 8

问题描述

我尝试按照以下教程在 Angular 8 中实现 JWT 刷新,但没有成功:

https://angular-academy.com/angular-jwt/#refresh-token

https://github.com/tjgweb/curso-laravel-jwt-angular/blob/v20-21-22/web/src/app/interceptors/refresh-token.interceptor.ts

我创建了一个拦截器,但如果我不订阅令牌刷新不起作用。如果我订阅令牌刷新服务,它可以工作,但我必须从浏览器为整个页面充电。

我正在使用 Angular 8 + Ionic4

拦截器.ts

import { Injectable } from '@angular/core';
import {
  HttpEvent,
  HttpInterceptor,
  HttpHandler,
  HttpRequest,
  HttpResponse,
  HttpHeaders,
  HttpErrorResponse,
  HttpClient
} from '@angular/common/http';
import { Observable, from, BehaviorSubject, throwError } from 'rxjs';
import { tap, flatMap, catchError, mergeMap, switchMap, filter, take, finalize } from 'rxjs/operators';
import { environment } from '../environments/environment';
import { Router } from '@angular/router';
import { LoadingController } from '@ionic/angular';
import {NativeStorage} from '@ionic-native/native-storage/ngx';
import { SecurityService } from './services/security.service';

@Injectable()
export class APIInterceptor implements HttpInterceptor {
  isLoading = false;
  Token;
  flagToken = false;
  private isRefreshing = false;
  private refreshTokenSubject: BehaviorSubject<any> = new BehaviorSubject<any>(null);
  constructor(
    private router: Router,
    private http: HttpClient,
    private loadingController: LoadingController,
    private securityStorageService: SecurityService,
    public nativeStorage: NativeStorage
  ) {
  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    console.log('URL INTERCEPTOR', `${environment.url}/${req.url}`);
    if (req.url === 'Token') {
      const apiReq = req.clone({ url: `${environment.url}/${req.url}` });
      return next.handle(apiReq);
    } else {
      return from(this.securityStorageService.getToken()).pipe(mergeMap(
        (token) => {
          // tslint:disable-next-line:prefer-const
          let newReq = req.clone(
            {
              headers: req.headers.set('Authorization', token)
                .set('Authorization-Type', 'JWT')
                .set('Content-Type', 'application/json')
                .set('Cache-Control', 'no-cache')
                .set('Pragma', 'no-cache'),
              url: `${environment.url}/${req.url}`
            });
          this.presentLoading();
          return next.handle(newReq).pipe(
              tap(event => {
                if (event instanceof HttpResponse) {
                  console.log('Interceptor - HttpResponse = ' + event.status); // http response status code
                  this.dismissLoading();
                }
              }, error => {
                this.dismissLoading();
                // http response status code
                if (error instanceof HttpErrorResponse) {
                  console.log('----response----');
                  console.error('status code:');
                  console.log('ERRORE CALLBACK', error);
                  console.error(error.status);
                  console.error(error.message);
                  console.log('--- end of response---');
                  if (error.status === 401) {
                    console.log('401');
                    return this.handle401Error(newReq, next);
                  } else {
                    return throwError(error);
                  }
                }
               // return Observable.throw(error);
              })
            );
        }
      ));
    }


  }

  private handle401Error(request: HttpRequest<any>, next: HttpHandler) {
    console.log('ISREFRESHING VALUE', this.isRefreshing);
    if (!this.isRefreshing) {
      console.log('JWT IN IF SUBJECT');
      this.isRefreshing = true;
      this.refreshTokenSubject.next(null);
      console.log('REFRESH SUBJECT NULL');
      let params = {};
      this.nativeStorage.getItem('refreshToken').then(
        (data) => {
          console.log('NATIVE STORAGE RTOKEN', data);
          params = {
            RToken: data
          };
          return this.securityStorageService.refreshToken(params).pipe(
            switchMap((token: any) => {
              console.log('SWITCHMAP TOKEN', token);
              this.isRefreshing = false;
              this.refreshTokenSubject.next(token.Token);
              return next.handle(this.addToken(request, token.Token)).pipe(
                tap(error => {console.log('ERRORE IN NEXT HANDLE', error)})
              );
            }),
          catchError(err => {
            console.log('ERRORE REFRESH TOKEN - LOGOUT APP', err);
            return this.router.navigate(['/login']);
          }),
          finalize(() => {
            this.isRefreshing = false;
          })
          )/*.subscribe(
            (rs) => {console.log('TOKEN REFRESH SUBSCRIBE', rs);}
          );*/
        }
      );

    } else {
      console.log('ELSE SUBJECT TOKEN');
      return this.refreshTokenSubject.pipe(
        filter(token => token != null),
        take(1),
        switchMap(jwt => {
          console.log('JWT IN ELSE SUBJECT', jwt);
          return next.handle(this.addToken(request, jwt.Token));
        }));
    }
  }

  private addToken(request: HttpRequest<any>, token: string) {
    return request.clone({
      headers: request.headers.set('Authorization', token)
      .set('Authorization-Type', 'JWT')
      .set('Content-Type', 'application/json')
      .set('Cache-Control', 'no-cache')
      .set('Pragma', 'no-cache')
      // url: `${environment.url}/${request.url}`
    });
  }

// Creación del loading
async presentLoading() {
  this.isLoading = true;
  return await this.loadingController.create({
    message: 'Caricamento in corso...',
    translucent: true,
    duration: 1000,
  }).then(a => {
    a.present().then(() => {
      if (!this.isLoading) {
        a.dismiss().then(() => console.log());
      }
    });
  });
}
// Cierre del loading
async dismissLoading() {
  this.isLoading = false;
  return await this.loadingController.dismiss().then(() => console.log('dismissed'));
}

}

安全服务.ts


import { Injectable } from '@angular/core';
import { NativeStorage } from '@ionic-native/native-storage/ngx';
import { HttpClientModule, HttpClient } from '@angular/common/http';
import { tap, catchError } from 'rxjs/operators';
import { Tokens } from '../models/tokens';
import { Observable, throwError } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class SecurityService {

  constructor(public nativeStorage: NativeStorage, private http: HttpClient) { }

  public async getToken() {
    return await this.nativeStorage.getItem('token');
  }

  refreshToken(params) {
        return this.http.post<any>(`RToken/?`, params)
        .pipe(tap((risultato: Tokens) => {
          console.log('TOKEN FROM SERVER', risultato);
          this.nativeStorage.setItem('token', risultato.token);
          this.nativeStorage.setItem('refreshToken', risultato.refreshToken);
        }),
        catchError(err => {
          console.log('ERRORE CHIAMATA RTOKEN', err);
          return throwError(err);
        })
        );
      }

}

谢谢

标签: angulartypescriptionic-frameworkrxjs

解决方案


推荐阅读