我正在开发一个OAuth2令牌系统,用于访问我的REST API,并在Android应用程序中使用。我在客户端的令牌刷新部分遇到了一些问题。
流程如下:我的应用程序通过一些异步任务(
示例1:
请求
编辑:
我最终选择使用
以下是
流程如下:我的应用程序通过一些异步任务(
PostCommentAsyncTask()
、AddFriendAsyncTask()
等)向服务器发送请求(带有访问令牌参数)。如果accessToken有效,那就没问题,但是如果过期了,我会从之前的AsyncTask
的onPostExecute()
方法中调用另一个AsyncTask
(GetRefreshTokenAsyncTask()
)来获取新的accessToken。这对我来说是棘手的部分。当我获得新的访问令牌时,我想重新执行最初的异步任务请求到服务器。我无法找出如何正确地执行它。示例1:
请求
PostCommentAsyncTask()
-->(acessToken过期)-->GetRefreshTokenAsyncTask()
-->请求PostCommentAsyncTask()
-->(好的token)-->好的编辑:
我最终选择使用
Volley
库(不再需要使用Asynctask)。
由于我使用JSON Web Token,我可以检查令牌负载中编码的到期日期。以下是
isAccessTokenExpired()
方法,用于在向服务器发送请求之前检查Access Token是否已过期:public Boolean isAccessTokenExpired(String accessToken){
String[] accessTokenPart = accessToken.split("\\.");
String header =accessTokenPart[0];
String payload =accessTokenPart[1];
String signature =accessTokenPart[2];
try {
byte[] decodedPayload = Base64.decode(payload, Base64.DEFAULT);
payload = new String(decodedPayload,"UTF-8");
} catch(UnsupportedEncodingException e) {
e.printStackTrace();
}
try {
JSONObject obj = new JSONObject(payload);
int expireDate = obj.getInt("exp");
Timestamp timestampExpireDate= new Timestamp( expireDate);
long time = System.currentTimeMillis();
Timestamp timestamp = new Timestamp(time);
return timestamp.after(timestampExpireDate);
} catch (JSONException e) {
e.printStackTrace();
return true;
}
}
这里有一个refreshJsonWebToken()
方法,可以从我的OAUTH2服务器获取新的访问令牌/刷新令牌:
public void refreshJsonWebToken(){
SharedPreferences settings = getActivity().getSharedPreferences(PREFS_NAME, 0);
String refreshToken = settings.getString("refreshToken", null);
final HashMap<String, String> params = new HashMap<String, String>();
params.put("grant_type","refresh_token");
params.put("client_id","client");
params.put("refresh_token",refreshToken);
JsonObjectRequest req = new JsonObjectRequest(URL_OAUTH2, new JSONObject(params), new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
try {
String newRefreshToken = response.getString("refresh_token");
SharedPreferences settings = getActivity().getSharedPreferences(PREFS_NAME, 0);
SharedPreferences.Editor editor = settings.edit();
editor.putString("accessToken", newAccessToken);
editor.putString("refreshToken", newRefreshToken);
editor.apply();
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e("grid", "Error: " + error.getMessage());
}
}
});
AppController.getInstance().addToRequestQueue(req);
}
最后是 getPost()
方法,其中我使用了前面的方法:
private void getPost(String latitude, String longitude) {
SharedPreferences settings = getActivity().getSharedPreferences(PREFS_NAME, 0);
String accessToken = settings.getString("accessToken", null);
final HashMap<String, String> params = new HashMap<String, String>();
params.put("action", "getLocalPosts");
params.put("latitude", latitude);
params.put("longitude", longitude);
if (isAccessTokenExpired(accessToken)){
refreshJsonWebToken();
}
settings = getActivity().getSharedPreferences(PREFS_NAME, 0);
accessToken = settings.getString("accessToken", null);
JsonObjectRequest req = new JsonObjectRequest(URL_APP+accessToken, new JSONObject(params), new Response.Listener<JSONObject>() {
//Some code ....
});
AppController.getInstance().addToRequestQueue(req);
}