Refresh token Angular

时光毁灭记忆、已成空白 提交于 2020-07-23 06:17:11

问题


I have created a service for calling API from my angular application. In that service, I have declared ROOT_URL and TOKEN variables and assigned values for these.

Below the declaration, there are few get methods to API using the above ROOT_URL and TOKEN.

Issue i am facing is, this TOKEN value is expired every 24 hours so that i have to change the value everyday. I use the previous TOKEN to get a refresh token using postman.

Can some one give me a solution how can i implement this will happen automatically every time when TOKEN expires?


回答1:


You can make use of the HTTP interceptor. You can check this article from Angular Academy.

Below you can find an example which I have implemented according to my needs (I have used that article as a starting point for this implementation). This example assumes that you're generating a refresh token on your back-end. On my back-end, I'm generating an access token (with a short living duration) and a refresh token (with a higher living duration). I'm using the refresh tokens only for generating new access tokens and not for authorization. You can store the tokens for example on local storage or cookie and retrieve them from there in a service.

import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HttpErrorResponse } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { switchMap, catchError } from 'rxjs/operators';
import { AuthService } from './auth.service';
import { IUserResponse } from '../shared/user.model';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  // for avoiding entering an infinite loop
  private isRefreshing = false;

  constructor(private authService: AuthService) {}

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (this.authService.accessToken) {
      request = this.setToken(request, this.authService.accessToken);
    }

    return next.handle(request).pipe(
      catchError(error => {
        if (error instanceof HttpErrorResponse && error.status === 401 && this.authService.refreshToken) {
          return this.handleAuthorizationError(request, next);
        } else {
          return throwError(error);
        }
      })
    );
  }

  private setToken(request: HttpRequest<any>, token: string): HttpRequest<any> {
    return request.clone({ setHeaders: { Authorization: `Bearer ${token}` } });
  }

  private handleAuthorizationError(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (!this.isRefreshing) {
      this.isRefreshing = true;

     // I have created a route on my back-end to generate a new access token
      return this.authService.getRefreshToken().pipe(
        switchMap((response: IUserResponse) => {
          this.isRefreshing = false;

          return next.handle(this.setToken(request, response.user.accessToken));
        })
      );
    } else {
      return next.handle(request);
    }
  }
}



回答2:


Usually, the HTTP response header that comes from the API has something that indicates that this client once was authenticated but now has an expired token. Typically, the response header has a property called token-expired or www-authenticate; you have to check this before starting the refreshes token process.

Code sample:

AuthInterceptor

import { Injectable } from '@angular/core';
import {
  HttpInterceptor,
  HttpRequest,
  HttpHandler,
  HttpEvent,
  HttpErrorResponse
} from '@angular/common/http';
import { AuthService } from '../services/auth.service';
import { Observable, BehaviorSubject, throwError } from 'rxjs';
import { environment } from 'src/environments/environment';
import { filter, switchMap, take, catchError } from 'rxjs/operators';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  private tryingRefreshing = false;
  private refreshTokenSubject: BehaviorSubject<any> = new BehaviorSubject<any>(null);

  constructor(public authService: AuthService) { }

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const token = this.authService.getToken();
    request = this.addAuthorization(request, token);
    return next.handle(request).pipe(catchError(error => {
      if (error instanceof HttpErrorResponse && error.status === 401) {
        const tokenExpired = error.headers.get('token-expired');
        if (tokenExpired) {
          return this.handle401Error(request, next);
        }

        this.authService.logout();
        return throwError(error);
      } else {
        return throwError(error);
      }
    }));
  }

  private handle401Error(request: HttpRequest<any>, next: HttpHandler) {
    if (!this.tryingRefreshing) {
      this.tryingRefreshing = true;
      this.refreshTokenSubject.next(null);
      
     return this.authService.refreshToken().pipe(
        switchMap((token: any) => {
          this.tryingRefreshing = false;
          this.refreshTokenSubject.next(token);
          return next.handle(this.addAuthorization(request, token));
        }));

    } else {
      return this.refreshTokenSubject.pipe(
        filter(token => token != null),
        take(1),
        switchMap(jwt => {
          return next.handle(this.addAuthorization(request, jwt));
        }));
    }
  }

  addAuthorization(httpRequest: HttpRequest<any>, token: string) {
    return httpRequest = httpRequest.clone({
      setHeaders: {
        Authorization: `Bearer ${token}`
      }
    });
  }
}

Refresh token

This is just a sample method to show the share() approach.

    refreshToken(): Observable<string> {
    return this.http.post<any>(`${this.baseUrl}/auth/token/refresh-token`, {}, { withCredentials: true })
      .pipe(
        share(),
        map((authResponse) => {
          this.currentAuthSubject.next(authResponse);
          this.addToLocalStorage(authResponse);
          return authResponse.token;
        }));
}
 


来源:https://stackoverflow.com/questions/60744304/refresh-token-angular

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!