টোকেন রিফ্রেশের পরে কৌণিক 4 ইন্টারসেপ্টর পুনরায় চেষ্টা করার অনুরোধ


85

হাই, আমি কীভাবে নতুন কৌণিক ইন্টারসেপ্টরগুলি বাস্তবায়িত করব এবং 401 unauthorizedটোকেনকে রিফ্রেশ করে এবং অনুরোধটি পুনরায় চেষ্টা করে ত্রুটিগুলি পরিচালনা করতে চেষ্টা করছি to এটি যে গাইডটি আমি অনুসরণ করে চলেছি : https://ryanchenkie.com/angular-authentication-used-the-http-client-and-http-interceptors

আমি সফলভাবে ব্যর্থ অনুরোধগুলি ক্যাশে করছি এবং টোকেনটি রিফ্রেশ করতে পারি তবে পূর্বে ব্যর্থ হওয়া অনুরোধগুলি কীভাবে পুনরায় পাঠানো যায় তা আমি বুঝতে পারি না। আমি বর্তমানে যে রেজোলিউয়ারগুলি ব্যবহার করছি তার সাথে এটি কাজ করতেও চাই।

token.intercepor.ts

return next.handle( request ).do(( event: HttpEvent<any> ) => {
        if ( event instanceof HttpResponse ) {
            // do stuff with response if you want
        }
    }, ( err: any ) => {
        if ( err instanceof HttpErrorResponse ) {
            if ( err.status === 401 ) {
                console.log( err );
                this.auth.collectFailedRequest( request );
                this.auth.refreshToken().subscribe( resp => {
                    if ( !resp ) {
                        console.log( "Invalid" );
                    } else {
                        this.auth.retryFailedRequests();
                    }
                } );

            }
        }
    } );

প্রমাণীকরণ.সর্বস্ব.স.

cachedRequests: Array<HttpRequest<any>> = [];

public collectFailedRequest ( request ): void {
    this.cachedRequests.push( request );
}

public retryFailedRequests (): void {
    // retry the requests. this method can
    // be called after the token is refreshed
    this.cachedRequests.forEach( request => {
        request = request.clone( {
            setHeaders: {
                Accept: 'application/json',
                'Content-Type': 'application/json',
                Authorization: `Bearer ${ this.getToken() }`
            }
        } );
        //??What to do here
    } );
}

উপরের পুনরায় চেষ্টা করা ফাইলগুলি হ'ল আমি যা বের করতে পারি না। আমি কীভাবে অনুরোধগুলি পুনরায় পাঠাব এবং পুনরায় চেষ্টা করার পরে সেগুলি সমাধানের মাধ্যমে রুটে উপলব্ধ করব?

এটি যদি প্রাসঙ্গিক কোড হয় তবে তা এই সহায়তা করে: https://gist.github.com/joshharms/00d8159900897dc5bed45757e30405f9


4
আমারও একই সমস্যা আছে, এবং এর কোনও উত্তর নেই বলে মনে হচ্ছে।
সর্বশেষতম ট্রাইবুনাল

উত্তর:


99

আমার চূড়ান্ত সমাধান। সমান্তরাল অনুরোধ সঙ্গে কাজ করে।

আপডেট: কোডটি কৌনিক 9 / আরএক্সজেএস 6 এর সাথে আপডেট হয়েছে, রিফ্রেশ টোকেন ব্যর্থ হলে ত্রুটি পরিচালনা এবং লুপিং ঠিক করে

import { HttpRequest, HttpHandler, HttpInterceptor, HTTP_INTERCEPTORS } from "@angular/common/http";
import { Injector } from "@angular/core";
import { Router } from "@angular/router";
import { Subject, Observable, throwError } from "rxjs";
import { catchError, switchMap, tap} from "rxjs/operators";
import { AuthService } from "./auth.service";

export class AuthInterceptor implements HttpInterceptor {

    authService;
    refreshTokenInProgress = false;

    tokenRefreshedSource = new Subject();
    tokenRefreshed$ = this.tokenRefreshedSource.asObservable();

    constructor(private injector: Injector, private router: Router) {}

    addAuthHeader(request) {
        const authHeader = this.authService.getAuthorizationHeader();
        if (authHeader) {
            return request.clone({
                setHeaders: {
                    "Authorization": authHeader
                }
            });
        }
        return request;
    }

    refreshToken(): Observable<any> {
        if (this.refreshTokenInProgress) {
            return new Observable(observer => {
                this.tokenRefreshed$.subscribe(() => {
                    observer.next();
                    observer.complete();
                });
            });
        } else {
            this.refreshTokenInProgress = true;

            return this.authService.refreshToken().pipe(
                tap(() => {
                    this.refreshTokenInProgress = false;
                    this.tokenRefreshedSource.next();
                }),
                catchError(() => {
                    this.refreshTokenInProgress = false;
                    this.logout();
                }));
        }
    }

    logout() {
        this.authService.logout();
        this.router.navigate(["login"]);
    }

    handleResponseError(error, request?, next?) {
        // Business error
        if (error.status === 400) {
            // Show message
        }

        // Invalid token error
        else if (error.status === 401) {
            return this.refreshToken().pipe(
                switchMap(() => {
                    request = this.addAuthHeader(request);
                    return next.handle(request);
                }),
                catchError(e => {
                    if (e.status !== 401) {
                        return this.handleResponseError(e);
                    } else {
                        this.logout();
                    }
                }));
        }

        // Access denied error
        else if (error.status === 403) {
            // Show message
            // Logout
            this.logout();
        }

        // Server error
        else if (error.status === 500) {
            // Show message
        }

        // Maintenance error
        else if (error.status === 503) {
            // Show message
            // Redirect to the maintenance page
        }

        return throwError(error);
    }

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<any> {
        this.authService = this.injector.get(AuthService);

        // Handle request
        request = this.addAuthHeader(request);

        // Handle response
        return next.handle(request).pipe(catchError(error => {
            return this.handleResponseError(error, request, next);
        }));
    }
}

export const AuthInterceptorProvider = {
    provide: HTTP_INTERCEPTORS,
    useClass: AuthInterceptor,
    multi: true
};

4
@ আন্ড্রেইস্ট্রোভস্কি, আপনি দয়া করে উত্তর importsএবং অথ সার্ভিসের কোডটি আপডেট করতে পারবেন?
তাকেশিন

4
আমার অনুভূতি আছে যে যদি কোনও কারণে this.authService.refreshToken () ব্যর্থ হয় তবে রিফ্রেশের জন্য অপেক্ষা করা সমস্ত সমান্তরাল প্রশ্নগুলি চিরকাল অপেক্ষা করবে।
মাকসিম গুমেরভ

4
রিফ্রেশ টোকেনে ধরা আমাকে কখনই ডাকবে না। এটি পর্যবেক্ষণযোগ্য .থ্রো।
জেমসেম্পডব্লু

4
বন্ধুরা, এটি সমান্তরাল এবং ক্রমানুসারে অনুরোধগুলির সাথে কাজ করে। আপনি 5 টি অনুরোধ প্রেরণ করুন, তারা 401 ফেরত দেয়, তারপরে 1 রিফ্রেশ টোকেন সম্পাদিত হয় এবং আবার 5 টি অনুরোধ। যদি আপনার 5 টি অনুরোধ ক্রমানুসারে হয় তবে প্রথম 401 এর পরে আমরা রিফ্রেশ টোকেন প্রেরণ করি, তারপরে আবার প্রথম অনুরোধ এবং অন্যান্য 4 টি অনুরোধ।
আন্দ্রে ওস্ট্রভস্কি

4
আপনি কেন ম্যানুয়ালি কোনও পরিষেবা ইনজেক্ট করছেন যখন অ্যাংুলার আপনার জন্য এটি করতে পারত যদি আপনি এটি সজ্জিত করেন @Injectable()? এছাড়াও একটি ক্যাচআরারর কিছুই ফেরায় না। কমপক্ষে ফিরবেন EMPTY
গ্যারি স্যান্ডর

16

অ্যাঙ্গুলার (.0.০.০) এবং আরএক্সজেএস (.3.৩.৩) এর সর্বশেষতম সংস্করণ সহ, আমি এটিরূপে সম্পূর্ণরূপে কার্যকরী অটো সেশন পুনরুদ্ধার ইন্টারসেপ্টর তৈরি করেছি, যদি সহবর্তী অনুরোধগুলি 401 দিয়ে ব্যর্থ হয়, তবে এটি কেবল টোকেন রিফ্রেশ এপিআইতে আঘাত করা উচিত একবার এবং সুইচম্যাপ এবং সাবজেক্ট ব্যবহার করে এর প্রতিক্রিয়ায় ব্যর্থ অনুরোধগুলি পাইপ করুন। নীচে আমার ইন্টারসেপ্টর কোডটি কেমন দেখাচ্ছে। আমি আমার লেখক পরিষেবা এবং স্টোর পরিষেবার জন্য কোডটি বাদ দিয়েছি কারণ তারা বেশ মানসম্পন্ন পরিষেবা ক্লাস।

import {
  HttpErrorResponse,
  HttpEvent,
  HttpHandler,
  HttpInterceptor,
  HttpRequest
} from "@angular/common/http";
import { Injectable } from "@angular/core";
import { Observable, Subject, throwError } from "rxjs";
import { catchError, switchMap } from "rxjs/operators";

import { AuthService } from "../auth/auth.service";
import { STATUS_CODE } from "../error-code";
import { UserSessionStoreService as StoreService } from "../store/user-session-store.service";

@Injectable()
export class SessionRecoveryInterceptor implements HttpInterceptor {
  constructor(
    private readonly store: StoreService,
    private readonly sessionService: AuthService
  ) {}

  private _refreshSubject: Subject<any> = new Subject<any>();

  private _ifTokenExpired() {
    this._refreshSubject.subscribe({
      complete: () => {
        this._refreshSubject = new Subject<any>();
      }
    });
    if (this._refreshSubject.observers.length === 1) {
      this.sessionService.refreshToken().subscribe(this._refreshSubject);
    }
    return this._refreshSubject;
  }

  private _checkTokenExpiryErr(error: HttpErrorResponse): boolean {
    return (
      error.status &&
      error.status === STATUS_CODE.UNAUTHORIZED &&
      error.error.message === "TokenExpired"
    );
  }

  intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    if (req.url.endsWith("/logout") || req.url.endsWith("/token-refresh")) {
      return next.handle(req);
    } else {
      return next.handle(req).pipe(
        catchError((error, caught) => {
          if (error instanceof HttpErrorResponse) {
            if (this._checkTokenExpiryErr(error)) {
              return this._ifTokenExpired().pipe(
                switchMap(() => {
                  return next.handle(this.updateHeader(req));
                })
              );
            } else {
              return throwError(error);
            }
          }
          return caught;
        })
      );
    }
  }

  updateHeader(req) {
    const authToken = this.store.getAccessToken();
    req = req.clone({
      headers: req.headers.set("Authorization", `Bearer ${authToken}`)
    });
    return req;
  }
}

@ অ্যান্টন-টোশিক মন্তব্য অনুসারে, আমি মনে করি লিখিতভাবে এই কোডটির কার্যকারিতাটি ব্যাখ্যা করা ভাল ধারণা। এই কোডটির ব্যাখ্যা এবং বোঝার জন্য আপনি এখানে আমার নিবন্ধটিতে একটি পঠন করতে পারেন (কীভাবে এবং কেন এটি কাজ করে?)। আশা করি এটা সাহায্য করবে.


4
ভাল কাজ, দ্বিতীয় returnভিতরে interceptফাংশন এই মত হওয়া উচিত: return next.handle(this.updateHeader(req)).pipe(। বর্তমানে আপনি কেবলমাত্র
তাজিকরণের

আমি মনে করি আমি এটি সুইচম্যাপের মাধ্যমে করছি। আবার চেক করুন. আমি যদি আপনার বক্তব্য ভুল বুঝি তবে আমাকে জানান।
সমরপণ

হ্যাঁ এটি মূলত কাজ করে তবে আপনি সর্বদা দুবার অনুরোধটি পাঠান - একবার শিরোনাম ছাড়াই এবং তারপরে এটি
শিরোনামটির

@ সমর্পনভাট্টাচার্য এটি কাজ করে। আমি মনে করি এই উত্তরটি আমার মতো কারও জন্য শব্দার্থবিজ্ঞানের ব্যাখ্যা দিয়ে করতে পারে যারা পর্যবেক্ষণের কাজটি বুঝতে পারে না।
আন্তন তোশিক

4
@ নিকাকুরাশভিলি, এই পদ্ধতির সংজ্ঞাটি আমার পক্ষে কাজ করেছে:public refreshToken(){const url:string=environment.apiUrl+API_ENDPOINTS.REFRESH_TOKEN;const req:any={token:this.getAuthToken()};const head={};const header={headers:newHttpHeaders(head)};return this.http.post(url,req,header).pipe(map(resp=>{const actualToken:string=resp['data'];if(actualToken){this.setLocalStorage('authToken',actualToken);}return resp;}));}
শ্রীনিবাস

9

আমি একই ধরণের সমস্যায় পড়েছি এবং আমার মনে হয় সংগ্রহ / পুনরায় চেষ্টা করার যুক্তি অতিরিক্ত জটিল। পরিবর্তে, আমরা কেবল 401 টি পরীক্ষা করার জন্য ক্যাচ অপারেটরটি ব্যবহার করতে পারি, তারপরে টোকেন রিফ্রেশের জন্য নজর রাখি এবং অনুরোধটি পুনরায় চালু করতে পারি:

return next.handle(this.applyCredentials(req))
  .catch((error, caught) => {
    if (!this.isAuthError(error)) {
      throw error;
    }
    return this.auth.refreshToken().first().flatMap((resp) => {
      if (!resp) {
        throw error;
      }
      return next.handle(this.applyCredentials(req));
    });
  }) as any;

...

private isAuthError(error: any): boolean {
  return error instanceof HttpErrorResponse && error.status === 401;
}

4
401 এর বিপরীতে মেয়াদোত্তীর্ণ টোকেন সনাক্ত করতে আমি 498 এর একটি কাস্টম স্থিতি কোড ব্যবহার করতে চাই যা এতে পর্যাপ্ত বেসরকারী নাও হতে পারে
জোসেফ ক্যারল

4
হাই, রিটার্ন পরবর্তী ব্যবহারের চেষ্টা করছি hand authService.createToken (authToken, রিফ্রেশ টোকেন); this.inflightAuthRequest = নাল; Next.handle (req.clone ({শিরোলেখ: req.headers.set (appGlobals.AUTH_TOKEN_KEY, authToken)})) ফিরে আসুন;

6
সংগ্রহ / পুনরায় চেষ্টা যুক্তি অত্যধিক জটিল নয়, আপনার টোকেনটির মেয়াদ শেষ হওয়ার পরে আপনি যদি রিফ্রেশ টোকেন শেষ পয়েন্টে একাধিক অনুরোধ করতে না চান তবে আপনাকে এটি করতে হবে। আপনার টোকেনটির মেয়াদ শেষ হয়ে গেছে বলে দিন এবং আপনি প্রায় একই সময়ে 5 টি অনুরোধ করেন। এই মন্তব্যে যুক্তি দিয়ে, 5 টি নতুন রিফ্রেশ টোকেন সার্ভার সাইড তৈরি করা হবে।
মারিউস লাজার

4
@ জোসেফকারল সাধারণত 403
andrea.spot এর মতো

9

আন্দ্রে ওস্ট্রোভস্কির চূড়ান্ত সমাধানটি সত্যিই ভাল কাজ করে তবে রিফ্রেশ টোকেনটির মেয়াদও শেষ হয়ে গেলে (কাজটি করে ধরে না আপনি রিফ্রেশ করার জন্য এপিআই কল করছেন)। কিছু খনন করার পরে, আমি বুঝতে পারি যে রিফ্রেশ টোকেন এপিআই কলটিও ইন্টারসেপ্টার দ্বারা আটকানো হয়েছিল। এটি পরিচালনা করতে আমাকে একটি বিবৃতি যোগ করতে হবে।

 intercept( request: HttpRequest<any>, next: HttpHandler ):Observable<any> {
   this.authService = this.injector.get( AuthenticationService );
   request = this.addAuthHeader(request);

   return next.handle( request ).catch( error => {
     if ( error.status === 401 ) {

     // The refreshToken api failure is also caught so we need to handle it here
       if (error.url === environment.api_url + '/refresh') {
         this.refreshTokenHasFailed = true;
         this.authService.logout();
         return Observable.throw( error );
       }

       return this.refreshAccessToken()
         .switchMap( () => {
           request = this.addAuthHeader( request );
           return next.handle( request );
         })
         .catch((err) => {
           this.refreshTokenHasFailed = true;
           this.authService.logout();
           return Observable.throw( err );
         });
     }

     return Observable.throw( error );
   });
 }

আপনি refreshTokenHasFailedসদস্য বুলিয়ান সাথে অন্য কোথাও খেলতে পারবেন তা দেখাতে পারেন ?
স্টিফেন

4
আপনি এটি আন্দ্রেই ওস্ট্রোভস্কির উপরের সমাধানটিতে সন্ধান করতে পারেন, আমি মূলত এটি ব্যবহার করেছি তবে রিফ্রেশ শেষ পয়েন্টটি বাধা দেওয়া হলে হ্যান্ডেল করার জন্য if স্টেটমেন্ট যুক্ত করেছি।
জেমস লিউ

এটি অর্থবোধ করে না, কেন রিফ্রেশ 401 ফেরত দেবে? বিন্দুর সাহায্যে রিফ্রেশ ডাকছে পর প্রমাণীকরণ ব্যর্থ হয়েছে, তাই আপনার রিফ্রেশ এপিআই এ সব অনুমোদন করা উচিত হবে না, এবং একটি 401. ফিরে আসবে না উচিত
MDave

রিফ্রেশ টোকেনগুলির মেয়াদ শেষ হতে পারে। আমাদের ব্যবহারের ক্ষেত্রে, এটি 4 ঘন্টা পরে সমাপ্ত হওয়ার জন্য সেট করা হয়েছিল, যদি ব্যবহারকারী দিনের শেষে তাদের ব্রাউজারটি বন্ধ করে দেয় এবং পরের দিন সকালে ফিরে আসে, রিফ্রেশ টোকেনটি সেই বিন্দুতে শেষ হয়ে গিয়েছিল এবং তাই আমাদের তাদের লগ করার প্রয়োজন হয়েছিল আবার ফিরে। যদি আপনার রিফ্রেশ টোকেনটির মেয়াদ শেষ না হয় তবে অবশ্যই আপনার এই যুক্তিটি প্রয়োগ করার প্রয়োজন হবে না
জেমস লিউ

4

এই উদাহরণের উপর ভিত্তি করে , এখানে আমার টুকরা

@Injectable({
    providedIn: 'root'
})
export class AuthInterceptor implements HttpInterceptor {

    constructor(private loginService: LoginService) { }

    /**
     * Intercept request to authorize request with oauth service.
     * @param req original request
     * @param next next
     */
    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<any> {
        const self = this;

        if (self.checkUrl(req)) {
            // Authorization handler observable
            const authHandle = defer(() => {
                // Add authorization to request
                const authorizedReq = req.clone({
                    headers: req.headers.set('Authorization', self.loginService.getAccessToken()
                });
                // Execute
                return next.handle(authorizedReq);
            });

            return authHandle.pipe(
                catchError((requestError, retryRequest) => {
                    if (requestError instanceof HttpErrorResponse && requestError.status === 401) {
                        if (self.loginService.isRememberMe()) {
                            // Authrozation failed, retry if user have `refresh_token` (remember me).
                            return from(self.loginService.refreshToken()).pipe(
                                catchError((refreshTokenError) => {
                                    // Refresh token failed, logout
                                    self.loginService.invalidateSession();
                                    // Emit UserSessionExpiredError
                                    return throwError(new UserSessionExpiredError('refresh_token failed'));
                                }),
                                mergeMap(() => retryRequest)
                            );
                        } else {
                            // Access token failed, logout
                            self.loginService.invalidateSession();
                            // Emit UserSessionExpiredError
                            return throwError(new UserSessionExpiredError('refresh_token failed')); 
                        }
                    } else {
                        // Re-throw response error
                        return throwError(requestError);
                    }
                })
            );
        } else {
            return next.handle(req);
        }
    }

    /**
     * Check if request is required authentication.
     * @param req request
     */
    private checkUrl(req: HttpRequest<any>) {
        // Your logic to check if the request need authorization.
        return true;
    }
}

আপনি চেষ্টা করতে পারেন যে ব্যবহারকারী Remember Meপুনরায় চেষ্টা করার জন্য রিফ্রেশ টোকেন ব্যবহার করতে সক্ষম হয়েছে কিনা বা লগআউট পৃষ্ঠাতে পুনর্নির্দেশ করতে পারে।

ফাই, এর LoginServiceনিম্নলিখিত পদ্ধতি রয়েছে:
- getAccessToken (): স্ট্রিং - access_token
বর্তমানটি ফিরিয়ে দিন - isRememberMe (): বুলিয়ান - ব্যবহারকারী আছে কিনা তা যাচাই করুন refresh_token
- রিফ্রেশটোকেন (): পর্যবেক্ষণযোগ্য / প্রতিশ্রুতি - নতুন access_tokenব্যবহারের জন্য ওউথ সার্ভারের অনুরোধ - অকার্যালিটিসেশন refresh_token
(): অকার্যকর - সমস্ত ব্যবহারকারীর তথ্য সরান এবং লগআউট পৃষ্ঠায় পুনর্নির্দেশ


একাধিক অনুরোধ একাধিক রিফ্রেশ অনুরোধ প্রেরণে আপনার কি সমস্যা আছে?
কোডিংগরিলা

এই সংস্করণটি আমি সর্বাধিক পছন্দ করি তবে আমার একটি সমস্যা রয়েছে যেখানে আমার একটি অনুরোধ জানায়, যখন 401 রিটার্নটি রিফ্রেশ করার চেষ্টা করা হয়, যখন প্রত্যাবর্তন ত্রুটি এটি ক্রমাগত চেষ্টা করে আবার অনুরোধটি প্রেরণ করে, কখনই থামবে না। আমি কি কিছু ভুল করছি?
জেমস্পডব্লু

দুঃখিত, আমি এর আগে আমি সাবধানতার সাথে পরীক্ষা করিনি। আমি যে পরীক্ষিত ব্যবহার করছি তার সাথে সবেমাত্র আমার পোস্টটি সম্পাদনা করা হয়েছে (এছাড়াও rxjs6 এ স্থানান্তরিত করুন এবং টোকেন রিফিশ করুন, url চেক করুন)।
থানহ নাহান

2

আমাকে নিম্নলিখিত প্রয়োজনীয়তাগুলি সমাধান করতে হয়েছিল:

  • Multiple একাধিক অনুরোধের জন্য শুধুমাত্র একবার টোকেন রিফ্রেশ করুন
  • Ref রিফ্রেশ টোকেন ব্যর্থ হলে ব্যবহারকারী লগ আউট করুন
  • First প্রথম রিফ্রেশ করার পরে যদি ব্যবহারকারী কোনও ত্রুটি পায় তবে লগ আউট করুন
  • To টোকেনটি রিফ্রেশ করার সময় সমস্ত অনুরোধের সন্ধান করুন

ফলস্বরূপ আমি কৌণিক টোকেন রিফ্রেশ করার জন্য বিভিন্ন বিকল্প সংগ্রহ করেছি:

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    let retries = 0;
    return this.authService.token$.pipe(
      map(token => req.clone({ setHeaders: { Authorization: `Bearer ${token}` } })),
      concatMap(authReq => next.handle(authReq)),
      // Catch the 401 and handle it by refreshing the token and restarting the chain
      // (where a new subscription to this.auth.token will get the latest token).
      catchError((err, restart) => {
        // If the request is unauthorized, try refreshing the token before restarting.
        if (err.status === 401 && retries === 0) {
          retries++;
    
          return concat(this.authService.refreshToken$, restart);
        }
    
        if (retries > 0) {
          this.authService.logout();
        }
    
        return throwError(err);
      })
    );
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return this.authService.token$.pipe(
      map(token => req.clone({ setHeaders: { Authorization: `Bearer ${token}` } })),
      concatMap(authReq => next.handle(authReq)),
      retryWhen((errors: Observable<any>) => errors.pipe(
        mergeMap((error, index) => {
          // any other error than 401 with {error: 'invalid_grant'} should be ignored by this retryWhen
          if (error.status !== 401) {
            return throwError(error);
          }
    
          if (index === 0) {
            // first time execute refresh token logic...
            return this.authService.refreshToken$;
          }
    
          this.authService.logout();
          return throwError(error);
        }),
        take(2)
        // first request should refresh token and retry,
        // if there's still an error the second time is the last time and should navigate to login
      )),
    );
}

এই সমস্ত অপশন ভয়াবহভাবে পরীক্ষা করা হয় এবং কৌণিক-রিফ্রেশ-টোকেন গিথুব রেপোতে পাওয়া যায়


1

আদর্শভাবে, আপনি isTokenExpiredঅনুরোধ প্রেরণের আগে পরীক্ষা করতে চান । এবং মেয়াদ উত্তীর্ণ হলে টোকেনটি রিফ্রেশ করুন এবং শিরোনামটিতে সতেজ করুন।

এ ছাড়া retry operator401 প্রতিক্রিয়াতে আপনার রিফ্রেশ টোকেনের যুক্তিকে সাহায্য করতে পারে।

RxJS retry operatorআপনি যেখানে অনুরোধ করছেন সেখানে আপনার পরিষেবাটি ব্যবহার করুন । এটি একটি retryCountযুক্তি গ্রহণ করে। যদি সরবরাহ না করা হয় তবে এটি অনির্দিষ্টকালের জন্য ক্রমটি আবার চেষ্টা করবে।

প্রতিক্রিয়াতে আপনার ইন্টারসেপ্টারে টোকেনটি রিফ্রেশ করুন এবং ত্রুটিটি ফিরিয়ে দিন। যখন আপনার পরিষেবা ত্রুটি ফিরে পেয়েছে তবে এখন আবার চেষ্টা করুন অপারেটর ব্যবহার করা হচ্ছে তাই এটি অনুরোধটি আবার চেষ্টা করবে এবং এবার রিফ্রেশ টোকেনের সাহায্যে (ইন্টারসেপ্টর হেডারে যুক্ত করতে রিফ্রেশড টোকেন ব্যবহার করে))

import {HttpClient} from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Rx';

@Injectable()
export class YourService {

  constructor(private http: HttpClient) {}

  search(params: any) {
    let tryCount = 0;
    return this.http.post('https://abcdYourApiUrl.com/search', params)
      .retry(2);
  }
}

0
To support ES6 syntax the solution needs to be bit modify and that is as following also included te loader handler on multiple request


        private refreshTokenInProgress = false;
        private activeRequests = 0;
        private tokenRefreshedSource = new Subject();
        private tokenRefreshed$ = this.tokenRefreshedSource.asObservable();
        private subscribedObservable$: Subscription = new Subscription();



 intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        if (this.activeRequests === 0) {
            this.loaderService.loadLoader.next(true);
        }
        this.activeRequests++;

        // Handle request
        request = this.addAuthHeader(request);

        // NOTE: if the flag is true it will execute retry auth token mechanism ie. by using refresh token it will fetch new auth token and will retry failed api with new token
        if (environment.retryAuthTokenMechanism) {
            // Handle response
            return next.handle(request).pipe(
                catchError(error => {
                    if (this.authenticationService.refreshShouldHappen(error)) {
                        return this.refreshToken().pipe(
                            switchMap(() => {
                                request = this.addAuthHeader(request);
                                return next.handle(request);
                            }),
                            catchError(() => {
                                this.authenticationService.setInterruptedUrl(this.router.url);
                                this.logout();
                                return EMPTY;
                            })
                        );
                    }

                    return EMPTY;
                }),
                finalize(() => {
                    this.hideLoader();
                })
            );
        } else {
            return next.handle(request).pipe(
                catchError(() => {
                    this.logout();
                    return EMPTY;
                }),
                finalize(() => {
                    this.hideLoader();
                })
            );
        }
    }

    ngOnDestroy(): void {
        this.subscribedObservable$.unsubscribe();
    }

    /**
     * @description Hides loader when all request gets complete
     */
    private hideLoader() {
        this.activeRequests--;
        if (this.activeRequests === 0) {
            this.loaderService.loadLoader.next(false);
        }
    }

    /**
     * @description set new auth token by existing refresh token
     */
    private refreshToken() {
        if (this.refreshTokenInProgress) {
            return new Observable(observer => {
                this.subscribedObservable$.add(
                    this.tokenRefreshed$.subscribe(() => {
                        observer.next();
                        observer.complete();
                    })
                );
            });
        } else {
            this.refreshTokenInProgress = true;

            return this.authenticationService.getNewAccessTokenByRefreshToken().pipe(tap(newAuthToken => {
            this.authenticationService.updateAccessToken(newAuthToken.access_token);
            this.refreshTokenInProgress = false;
            this.tokenRefreshedSource.next();
        }));
        }
    }

    private addAuthHeader(request: HttpRequest<any>) {
        const accessToken = this.authenticationService.getAccessTokenOnly();
        return request.clone({
            setHeaders: {
                Authorization: `Bearer ${accessToken}`
            }
        });
    }

    /**
     * @todo move in common service or auth service once tested
     * logout and redirect to login
     */
    private logout() {
        this.authenticationService.removeSavedUserDetailsAndLogout();
    }

আপনি কি প্রমাণীকরণের পরিষেবা ক্লাস যুক্ত করতে পারেন
এজেট

-3

আমি ব্যর্থ অনুরোধের url এবং ব্যর্থ অনুরোধের একই অংশটি প্রেরণের উপর ভিত্তি করে একটি নতুন অনুরোধ তৈরি করতে পেরেছি।

 retryFailedRequests() {

this.auth.cachedRequests.forEach(request => {

  // get failed request body
  var payload = (request as any).payload;

  if (request.method == "POST") {
    this.service.post(request.url, payload).subscribe(
      then => {
        // request ok
      },
      error => {
        // error
      });

  }
  else if (request.method == "PUT") {

    this.service.put(request.url, payload).subscribe(
      then => {
       // request ok
      },
      error => {
        // error
      });
  }

  else if (request.method == "DELETE")

    this.service.delete(request.url, payload).subscribe(
      then => {
        // request ok
      },
      error => {
        // error
      });
});

this.auth.clearFailedRequests();        

}


-4

আপনার প্রমাণীকরণ.সার্ভিস.স.গুলিতে আপনার নির্ভরতা হিসাবে একটি এইচটিটিপি ক্লায়েন্ট ইনজেকশন করা উচিত

constructor(private http: HttpClient) { }

তারপরে আপনি অনুরোধটি পুনরায় জমা দিতে পারবেন (পুনরায় চেষ্টা করা পুনরায় চেষ্টা করুন)

this.http.request(request).subscribe((response) => {
    // You need to subscribe to observer in order to "retry" your request
});

এটি আমার প্রাথমিক চিন্তা ছিল, তবে http.request প্রত্যাবর্তন HttpEvent
আন্তোনিওসস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.