使用拦截器获取refreshtoken后如何调用相同的请求?

Posted

技术标签:

【中文标题】使用拦截器获取refreshtoken后如何调用相同的请求?【英文标题】:How to call the same request after getting refreshtoken using interceptor? 【发布时间】:2020-03-19 10:20:20 【问题描述】:

我正在创建使用改造的 android 应用程序。我用spring作为rest api。我已经使用 JWT 进行身份验证。我在这里使用了两个拦截器RequestInterceptorResponseInterceptor。使用 expire JWT 调用BASE_URL/hello api 的场景如下

    客户端调用 /hello 使用 RequestInterceptor 标头中的过期访问令牌

    服务器检查令牌和响应代码为 401/403

    客户端检查响应代码并使用 ResponseInterceptor 调用 /refresh,并在 header 中使用 refreshtoken

    服务器检查刷新令牌并使用新的访问令牌响应

现在的问题是如何再次调用 /hello。对于每个请求,我都想要这个。我如何预测最后发出的请求。

代码如下:

调用 /hello 的部分代码

btnNext.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View view) 


                Call<HelloResponse> call= RetrofitFactoryWithJwt.getRetrofitInstance(getApplicationContext()).helloUser();

                call.enqueue(new Callback<HelloResponse>() 
                    @Override
                    public void onResponse(Call<HelloResponse> call, Response<HelloResponse> response) 
                        Log.d(TAG,"after call in enque");
                        if(response.code()==200)
                        
                            Log.d(TAG,response.body().getSuccess());
                        
                        else
                        
                            Log.d(TAG,"problem in response:"+response.code());

                        
                    

                    @Override
                    public void onFailure(Call<HelloResponse> call, Throwable t) 
                        Log.d(TAG,"onfailure"+t.getMessage());
                    
                );

                Intent intent = new Intent( getApplicationContext(), MainActivity.class);
                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
                startActivity(intent);
            
        );

RequestInterceptor.java

public class RequestInterceptor implements Interceptor 


   Context context;
  String TAG="heyrequest";

    public RequestInterceptor(Context context)
    
        this.context=context;
    
    @Override
    public Response intercept(Chain chain) throws IOException 

        Request originalRequest = chain.request();

        //if url is /refresh add refresh token in header instead of accesstoken
        if(originalRequest.url().encodedPath().equalsIgnoreCase("/refresh"))
        

            SharedPreferences preferences = context.getSharedPreferences("tokens", MODE_PRIVATE);
            String refreshvalue=preferences.getString("refreshtoken","");


            // rewrite the request
            Request newRequest=originalRequest.newBuilder()
                    .addHeader("Authorization","Bearer "+refreshvalue)
                    .build();

            return chain.proceed(newRequest);
        

      //for context we have use requestinterceptor context construction

        SharedPreferences preferences = context.getSharedPreferences("tokens", MODE_PRIVATE);
        String tokenvalue=preferences.getString("accesstoken","");

        // rewrite the request
        Request newRequest=originalRequest.newBuilder()
                            .addHeader("Authorization","Bearer "+tokenvalue)
                            .build();

        return chain.proceed(newRequest);
    


ResponseInterceptor.java

public class ResponseInterceptor implements Interceptor 

    Context context;
    String TAG="heyresponse";
    String accesstoken=null;
    Response response=null;
    public ResponseInterceptor(Context context)
    
       this.context=context;
    

    @Override
    public Response intercept(final Chain chain) throws IOException 

         final Request request=chain.request();
         response = chain.proceed(request);
        if(response.code()==401 || response.code()==403)
        
           accesstoken=getNewToken();
        
        return chain.proceed(request);
    

    public String getNewToken()
    

        Call<RefreshResponse> call= RetrofitFactoryWithJwt.getRetrofitInstance(context).refreshToken();

        call.enqueue(new Callback<RefreshResponse>() 
            @Override
            public void onResponse(Call<RefreshResponse> call, retrofit2.Response<RefreshResponse> response1) 
                Log.d(TAG,"in refreshtoken call");
                if(response1.code()==200)
                

                    accesstoken=response1.body().getAccesstoken();
                    Log.d(TAG,accesstoken);

                    SharedPreferences preferences = context.getSharedPreferences("tokens", MODE_PRIVATE);
                    preferences.edit().putString("accesstoken", accesstoken).apply();

                
                else
                
                    Log.d(TAG,"problem in response:"+response1.code());
                
            

            @Override
            public void onFailure(Call<RefreshResponse> call, Throwable t) 
                Log.d(TAG,"onfailure:"+t.getMessage());
            
        );

return  accesstoken;
    



【问题讨论】:

【参考方案1】:

我通过使用验证器处理响应和拦截器在请求中添加标头解决了这个问题

【讨论】:

以上是关于使用拦截器获取refreshtoken后如何调用相同的请求?的主要内容,如果未能解决你的问题,请参考以下文章

axios拦截器和异步登录

Angular 6在令牌更新后重制请求之前更改JWT令牌

Alamofire refreshToken with Retrier:如何获取 refreshToken 请求的状态并重新路由到 LoginView

使用OkHttp拦截器和Retrofit进行缓存

使用OkHttp拦截器和Retrofit进行缓存

java如何实现拦截短信功能