Pracuję nad systemem tokenów Oauth2, aby uzyskać dostęp do interfejsu API REST dla mojej aplikacji na Androida. Mam pewne problemy z częścią token refreshment po stronie klienta.Jak zaimplementować proces odświeżania tokena z JWT dla aplikacji na Androida
Oto przepływ: Moja aplikacja wysyła żądanie (z parametrem Token dostępu) do serwera dzięki asynktakowi (PostCommentAsyncTask()
, AddFriendAsyncTask()
itd.), Więc jeśli token dostępu jest ważny, to jest OK, ale jeśli jest stracił ważność Wywołuję inny AsyncTask
(GetRefreshTokenAsyncTask()
) z metodyz precedensu AsyncTask
, aby uzyskać nowy accessToken. Tutaj jest dla mnie trudna część. Kiedy otrzymam nowy token dostępu, chcę ponownie wykonać pierwsze żądanie AsyncTask na serwerze. Nie mogę wymyślić, jak to zrobić właściwie.
example1:
prośba PostCommentAsyncTask()
-> (acessToken wygasł) ->GetRefreshTokenAsyncTask()
-> prośba PostCommentAsyncTask()
-> (dobry znak) -> Ok
EDIT:
Ostatecznie zdecydowałem się użyć biblioteki Volley
(nie trzeba już używać Asynctask). Jak używam JSON Web Token
mogę sprawdzić datę ważności, która jest zakodowana w ładunku tokena.
Oto metoda isAccessTokenExpired()
aby sprawdzić, czy dostęp Reklamowe nie upłynął przed złożeniem żądania do serwera:
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;
}
}
A oto metoda refreshJsonWebToken()
dostać nową parę token dostępu/Refresh tokena z mojego serwera 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);
}
I Wreszcie dążyć metody getPost()
gdzie używam metody zawieszających:
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);
}
Możesz użyć metody 'get()' swojego drugiego 'AsyncTask' w 'doInBackground()' metoda twojego pierwszego 'AsyncTask'. Metoda 'get()' z 'AsyncTask' jest metodą blokującą, która zwraca wynik - użycie jej w wątku głównym/UI jest całkowicie bezużyteczne, ale jeśli wywołasz ją z pierwszego' DoInBackground() 'AsyncTask'() (która działa na własnym wątku), możesz po prostu kontynuować oryginalną czynność po zwróceniu drugiej metody 'get()' AsyncTask. Tylko pomysł. – Squonk
@ Frédéric: Jaką bibliotekę używałeś po stronie serwera do udzielania haseł OAuth2? Używam węzła jako zaplecza. – j10