身份验证 – 在使用Volley重试旧请求之前重新获取新令牌

身份验证 – 在使用Volley重试旧请求之前重新获取新令牌,第1张

概述我有一个使用Volley实现的简单身份验证系统.它是这样的: 登录时从服务器获取令牌 – >一小时后,此令牌过期 – >当它到期时,我们会发现API调用失败,所以我们应该(在重试时) – >在该呼叫失败时获取新令牌,然后 – >重试原始呼叫. 我已经实现了这个,并且令牌成功返回,但是因为我认为我对Volley RequestQueue做错了,原始请求在新的有效令牌能够被使用之前使用了所有它的重试. 我有一个使用Volley实现的简单身份验证系统.它是这样的:
登录时从服务器获取令牌 – >一小时后,此令牌过期 – >当它到期时,我们会发现API调用失败,所以我们应该(在重试时) – >在该呼叫失败时获取新令牌,然后 – >重试原始呼叫.

我已经实现了这个,并且令牌成功返回,但是因为我认为我对Volley RequestQueue做错了,原始请求在新的有效令牌能够被使用之前使用了所有它的重试.请参阅以下代码:

public class GeneralAPICall extends Request<JsONObject> {public static String LOG_TAG = GeneralAPICall.class.getSimplename();SessionManager sessionManager; //instance of sessionManager needed to get user's credentialsprivate Response.Listener<JsONObject> Listener; //the response Listener used to deliver the responseprivate Map<String,String> headers = new HashMap<>(); //the headers used to authenticateprivate Map<String,String> params; //the params to pass with API call,can be nullpublic GeneralAPICall(int method,String url,Map<String,String> params,Context context,Response.Listener<JsONObject> responseListener,Response.ErrorListener errorListener) {    super(method,url,errorListener);    sessionManager = new SessionManager(context); //instantiate    HashMap<String,String> credentials = sessionManager.getUserDetails(); //get the user's credentials for authentication    this.Listener = responseListener;    this.params = params;    //encode the user's username and token    String loginEncoded = new String(Base64.encode((credentials.get(Constants.SessionManagerConstants.KEY_USERname)            + Constants.APIConstants.Characters.CHAR_ColON            + credentials.get(Constants.SessionManagerConstants.KEY_TOKEN)).getBytes(),Base64.NO_WRAP));    Log.v(LOG_TAG,loginEncoded); //Todo: remove    this.headers.put(Constants.APIConstants.BasicAuth.AUTHORIZATION,Constants.APIConstants.BasicAuth.BASIC + loginEncoded); //set the encoded information as the header    setRetryPolicy(new TokenRetryPolicy(context)); //**THE RETRY POliCY**}

我设置的重试策略被定义为默认值,但我实现了自己的重试方法:

@OverrIDepublic voID retry(VolleyError error) throws VolleyError {    Log.v(LOG_TAG,"Initiating a retry");    mCurrentRetryCount++; //increment our retry count    mCurrentTimeoutMs += (mCurrentTimeoutMs * mBackoffMultiplIEr);    if (error instanceof AuthFailureError) { //we got a 401,and need a new token        Log.v(LOG_TAG,"AuthFailureError found!");        VolleyUser.refreshTokenTask(context,this); //**GET A NEW TOKEN**    }    if (!hasAttemptRemaining()) {        Log.v(LOG_TAG,"No attempt remaining,ERROR");        throw error;    }}

刷新令牌任务定义RefreshAPICall

public static voID refreshTokenTask(Context context,IRefreshTokenReturn Listener) {    Log.v(LOG_TAG,"refresh token task called");    final IRefreshTokenReturn callBack = Listener;    RefreshAPICall request = new RefreshAPICall(Request.Method.GET,Constants.APIConstants.URL.GET_TOKEN_URL,context,new Response.Listener<JsONObject>() {        @OverrIDe        public voID onResponse(JsONObject response) {            try {                String token = response.getString(Constants.APIConstants.Returns.RETURN_TOKEN);                Log.v(LOG_TAG,"Token from return is: " + token);                callBack.onTokenRefreshComplete(token);            } catch (JsONException e) {                callBack.onTokenRefreshComplete(null); //Todo: log this                e.printstacktrace();            }        }    },new Response.ErrorListener() {        @OverrIDe        public voID onErrorResponse(VolleyError error) {            Log.v(LOG_TAG,"Error with RETRY : " + error.toString());        }    });    VolleySingleton.getInstance(context).addToRequestQueue(request);}

我们的RefreshAPICall定义:

public RefreshAPICall(int method,String> credentials = sessionManager.getRefreshUserDetails(); //get the user's credentials for authentication    this.Listener = responseListener;    //encode the user's username and token    String loginEncoded = new String(Base64.encode((credentials.get(Constants.SessionManagerConstants.KEY_USERname)            + Constants.APIConstants.Characters.CHAR_ColON            + credentials.get(Constants.SessionManagerConstants.KEY_PASSWORD)).getBytes(),Base64.NO_WRAP));    this.headers.put(Constants.APIConstants.BasicAuth.AUTHORIZATION,Constants.APIConstants.BasicAuth.BASIC + loginEncoded); //set the encoded information as the header    setTag(Constants.VolleyConstants.RETRY_TAG); //mark the retry calls with a tag so we can delete any others once we get a new token    setPriority(Priority.IMMEDIATE); //set priority as immediate because this needs to be done before anything else    //deBUG lines    Log.v(LOG_TAG,"RefreshAPICall made with " + credentials.get(Constants.SessionManagerConstants.KEY_USERname) + " " +            credentials.get(Constants.SessionManagerConstants.KEY_PASSWORD));    Log.v(LOG_TAG,"Priority set on refresh call is " + getPriority());    Log.v(LOG_TAG,"Tag for Call is " + getTag());}

我将此请求的优先级设置为高,以便在失败之前触发,因此一旦我们获得令牌,原始调用就可以使用有效令牌触发.

最后,在响应时,我使用重试标记删除任何其他任务(如果多个API调用失败并进行多次重试调用,我们不希望多次覆盖新令牌)

@OverrIDepublic voID onTokenRefreshComplete(String token) {    VolleySingleton.getInstance(context).getRequestQueue().cancelAll(Constants.VolleyConstants.RETRY_TAG);    Log.v(LOG_TAG,"Cancelled all retry calls");    SessionManager sessionManager = new SessionManager(context);    sessionManager.setStoredToken(token);    Log.v(LOG_TAG,"Logged new token");}

不幸的是,LogCat告诉我在使用令牌之前所有的重试都在进行.令牌成功返回,但显然IMMEDIATE优先级对队列调度调用的顺序没有影响.

有关如何确保我的RefreshAPICall的任何帮助都会被激发,然后才会非常感谢其他任务.我想知道Volley是否将RefreshAPICall视为原始失败任务的子任务,因此它会尝试将该原始任务调用其重试次数,直到这些任务结束,然后触发RefreshAPICall.

LogCat(不知道如何让它看起来很漂亮):

05-05 16:12:07.145: E/Volley(1972): [137] BasicNetwork.performRequest: Unexpected response code **401 for https://url.me/API/get_frIEnds**05-05 16:12:07.145: V/TokenRetryPolicy(1972): Initiating a retry05-05 16:12:07.145: V/TokenRetryPolicy(1972): AuthFailureError found!05-05 16:12:07.146: V/VolleyUser(1972): refresh token task called05-05 16:12:07.146: V/RefreshAPICall(1972): RefreshAPICall made with username user_password05-05 16:12:07.147: V/RefreshAPICall(1972): Priority set on refresh call is HIGH05-05 16:12:07.147: V/RefreshAPICall(1972): Tag for Call is retry05-05 16:12:07.265: E/Volley(1972): [137] BasicNetwork.performRequest: Unexpected response code **401 for https://url.me/API/get_frIEnds**05-05 16:12:07.265: V/TokenRetryPolicy(1972): Initiating a retry05-05 16:12:07.265: V/TokenRetryPolicy(1972): AuthFailureError found!05-05 16:12:07.265: V/VolleyUser(1972): refresh token task called05-05 16:12:07.265: V/RefreshAPICall(1972): RefreshAPICall made with user user_password05-05 16:12:07.265: V/RefreshAPICall(1972): Priority set on refresh call is HIGH05-05 16:12:07.265: V/RefreshAPICall(1972): Tag for Call is retry05-05 16:12:07.265: V/TokenRetryPolicy(1972): No attempt remaining,ERROR05-05 16:12:08.219: I/Choreographer(1972): Skipped 324 frames!  The application may be doing too much work on its main thread.05-05 16:12:08.230: V/RefreshAPICall(1972): Response from server on refresh is: {"status":"success","token":"d5792e18c0e1acb3ad507dbae854eb2cdc5962a2c1b610a6b77e3bc3033c7f64"}05-05 16:12:08.230: V/VolleyUser(1972): Token from return is: d5792e18c0e1acb3ad507dbae854eb2cdc5962a2c1b610a6b77e3bc3033c7f6405-05 16:12:08.231: V/TokenRetryPolicy(1972): Cancelled all retry calls05-05 16:12:08.257: V/SessionManager(1972): New Token In SharedPref is: d5792e18c0e1acb3ad507dbae854eb2cdc5962a2c1b610a6b77e3bc3033c7f6405-05 16:12:08.257: V/TokenRetryPolicy(1972): Logged new token
解决方法 现在我发现了一个答案,我找到了一种在重试时处理令牌刷新的方法.

当我使用Volley创建我的一般(最常见)API调用时,如果失败则保存对该调用的引用,并将其传递给我的重试策略.

public GeneralAPICall(int method,errorListener);    sessionManager = SessionManager.getmInstance(context);    HashMap<String,String> credentials = sessionManager.getUserDetails(); // Get the user's credentials for authentication    this.Listener = responseListener;    this.params = params;    // Encode the user's username and token    String loginEncoded = new String(Base64.encode((credentials.get(Constants.SessionManagerConstants.KEY_USERname)            + Constants.APIConstants.Characters.CHAR_ColON            + credentials.get(Constants.SessionManagerConstants.KEY_TOKEN)).getBytes(),Constants.APIConstants.BasicAuth.BASIC + loginEncoded); // Set the encoded information as the header    setRetryPolicy(new TokenRetryPolicy(context,this)); //passing "this" saves the reference}

然后,在我的重试策略类(它只是扩展DefaultRetryPolicy,当我收到401错误告诉我需要一个新令牌时,我拍摄了一个refreshToken调用来获取一个新令牌.

public class TokenRetryPolicy extends DefaultRetryPolicy implements IRefreshTokenReturn{...@OverrIDepublic voID retry(VolleyError error) throws VolleyError {    mCurrentRetryCount++; //increment our retry count    mCurrentTimeoutMs += (mCurrentTimeoutMs * mBackoffMultiplIEr);    if (error instanceof AuthFailureError && sessionManager.isLoggedIn()) {        mCurrentRetryCount = mMaxnumRetrIEs + 1; // Don't retry anymore,it's pointless        VolleyUser.refreshTokenTask(context,this); // Get new token    } if (!hasAttemptRemaining()) {        Log.v(LOG_TAG,ERROR");        throw error;    }}...}

一旦该调用返回,我在我的重试策略类中处理响应.我修改失败的调用,给它新的令牌(在将标记存储在SharedPrefs中之后)进行身份验证,然后再将其激活!

@OverrIDepublic voID onTokenRefreshComplete(String token,String expiration) {    sessionManager.setStoredToken(token,expiration);    HashMap<String,String> credentials = sessionManager.getUserDetails(); //get the user's credentials for authentication    //encode the user's username and token    String loginEncoded = new String(Base64.encode((credentials.get(Constants.SessionManagerConstants.KEY_USERname)            + Constants.APIConstants.Characters.CHAR_ColON            + credentials.get(Constants.SessionManagerConstants.KEY_TOKEN)).getBytes(),loginEncoded); //Todo: remove    callThatFailed.setheaders(Constants.APIConstants.BasicAuth.AUTHORIZATION,Constants.APIConstants.BasicAuth.BASIC + loginEncoded); //modify "old,Failed" call - set the encoded information as the header    VolleySingleton.getInstance(context).getRequestQueue().add(callThatFailed);    Log.v(LOG_TAG,"fired off new call");}

这个实现对我很有用.

但是,我应该注意这种情况不应该发生太多,因为我知道在进行任何API调用之前我应该​​检查我的令牌是否已过期.这可以通过在SharedPrefs中存储到期时间(从服务器返回),并查看current_time – 到期时间< some_time,some_time是你想要在它到期之前得到一个新令牌的时间,对我来说是10秒. 希望这可以帮助那里的人,如果我错了什么,请评论!

总结

以上是内存溢出为你收集整理的身份验证 – 在使用Volley重试旧请求之前重新获取新令牌全部内容,希望文章能够帮你解决身份验证 – 在使用Volley重试旧请求之前重新获取新令牌所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://www.54852.com/web/1131378.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-30
下一篇2022-05-30

发表评论

登录后才能评论

评论列表(0条)

    保存