Rafraîchissant jeton OAuth à l'aide de Rénovation sans modifier tous les appels
Nous sommes à l'aide de Rénovation dans notre application Android, pour communiquer avec un OAuth2 serveur sécurisé. Tout fonctionne très bien, nous utilisons la RequestInterceptor pour inclure le jeton d'accès à chaque appel.
Cependant il y aura des moments, lorsque le jeton d'accès expirera, et le jeton doit être actualisé. Quand le jeton arrive à expiration, le prochain appel sera de retour avec une autorisation de code HTTP, donc c'est facile à surveiller.
Nous pourrions modifier chaque Rénovation d'appel de la manière suivante:
Dans le rappel d'échec, vérifiez le code d'erreur, si elle est égale à non autorisée, d'actualiser le jeton OAuth, puis répétez la Rénovation d'appel.
Cependant, pour cela, tous les appels doivent être modifiés, ce qui n'est pas facilement maintenable, et de la bonne solution.
Est-il un moyen de le faire sans modifier tous les de Rénovation des appels?
- Cela semble pertinent à mon autre question. Je vais regarder de nouveau bientôt, mais une approche possible est d'emballage OkHttpClient. Quelque chose comme ceci: github.com/pakerfeldt/signpost-retrofit Aussi, depuis que je suis en utilisant RoboSpice avec la Rénovation, de la création d'une classe de Requête de base peut être une autre approche possible ainsi. Probablement, vous aurez à comprendre comment obtenir votre flux sans un Contexte bien que, peut-être l'aide d'Otto/EventBus.
- Je trouve ça aussi étrange, que la Rénovation a été autour pendant un temps assez long, et OAuth2 est également utilisée de méthode d'authentification, et il n'y a pas de ressources sur cette. Panneau Rénovations semble prometteur, avez-vous encore essayé?
- Non, je pense qu'il n'est plus de ce dont j'ai besoin dans ce cas, comme je ne suis pas intéressé par la signature de la demande. Cependant emballage OkHttpClient comme Panneau-mise à niveau ne semble comme une solution viable, ou au moins un bon point de départ.
- Eh bien, vous pourriez fourche, et de supprimer les inutiles cas. Je vais regarder dans ce peut-être aujourd'hui, et de poster ici si j'ai obtenu quelque chose qui pourrait résoudre notre problème.
- J'ai regardé un peu plus profondément en elle, et il s'avère que le panneau ne peut pas gérer jeton rafraîchit. Cependant, j'ai trouvé une API wrapper pour GetGlue, qui utilise la rénovation, et les poignées de jeton actualise (cela utilise aussi une coutume OkHttpClient): github.com/UweTrottmann/getglue-java
- S'est avéré, que la bibliothèque n'a pas de poignée rafraîchissante jetons, mais m'a donné une idée. J'ai fait un petit résumé sur certains !code non testé, mais en théorie, je pense que cela devrait fonctionner: gist.github.com/ZolnaiDani/9710849
- Qui semble être dans la bonne direction, la partie la plus délicate serait l'annonce de la nouvelle jetons et la persistance d'eux. C'est là que vous devez obtenir un Contexte à partir de quelque part, ou de l'annoncer avec Otto/EventBus.
- J'ai mis à jour mon gist. Je vais installer un local serveur OAuth, et de tester des choses, je ne garantis pas le code de travail encore.
- J'aime bien ton résumé, mais que se passerait-il si deux demandes parallèles échoue sur jeton expiré et à la fois demander à nouveau?
- Une solution que je pense: faire de la changeTokenInRequest(...) synchronisée, et à la première ligne, vérifiez quand était la dernière fois que le jeton a été actualisé. S'il a été juste quelques secondes (en millisecondes) il y a, ne pas actualiser le jeton. Vous pouvez également définir ce laps de temps de 1 heure, arrêter sans cesse de demander de nouveaux jetons quand il y a un autre problème en dehors du jeton d'être dépassées.
- L'essentiel s'est déplacé à: gist.github.com/dzolnai/9710849
- Une façon de le faire en plus de l'extension de
OkHttp
serait tellement génial. - Rénovation 1.9.0 juste ajouté le support pour OkHttp 2.2, qui a intercepteurs. Cela devrait rendre votre travail beaucoup plus facile. Pour plus d'info, voir: github.com/square/retrofit/blob/master/... et github.com/square/okhttp/wiki/Interceptors Vous avez à étendre OkHttp pour ces trop, cependant.
- Certainement utiliser le nouveau Intercepteur API pour faire quelque chose comme ceci maintenant, si vous êtes en utilisant
OkHttp
. @DanielZolnai, vous avez réellement n'avez pas à étendreOkHttp
faire cela avec uneInterceptor
. Voir ma réponse ci-dessous.
Vous devez vous connecter pour publier un commentaire.
S'il vous plaît ne pas utiliser
Interceptors
pour s'occuper d'authentification.Actuellement, la meilleure approche pour gérer l'authentification consiste à utiliser la nouvelle
Authentificateur
API, conçu spécifiquement pour les cet effet.OkHttp sera automatiquement demander la
Authenticator
pour les informations d'identification lorsqu'une réponse est401 Not Authorised
nouvelle tentative de la dernière demande en échec avec eux.Joindre un
Authenticator
à unOkHttpClient
de la même manière que vous le faites avecInterceptors
Utiliser ce client lors de la création de votre
Retrofit
RestAdapter
response
classe?TokenAuthenticator
dépend d'unservice
classe. Leservice
classe dépend d'uneOkHttpClient
instance. Pour créer unOkHttpClient
j'ai besoin de laTokenAuthenticator
. Comment puis-je brise ce cycle? DeuxOkHttpClient
s? Ils vont avoir des différents pools de connexion...Authenticator
est également exécutée si le code de réponse est 407. Voir la doc.401
Authenticator
permettra d'actualiser le jeton et puis, le reste est ok (jusqu'à l'expiration de ce jeton de nouveau)OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder(); okHttpClientBuilder.authenticator(authAuthenticator); OkHttpClient okHttpClient = okHttpClientBuilder.build();
call.enqueue(callback)
vous devez utilisercall.execute()
.Authenticator
offre un hameçon pour capturer401
s. Cependant, je suis en désaccord avec l'énoncé "s'il vous Plaît ne pas utiliser d'Intercepteurs pour s'occuper d'authentification". En passant par la Place propre Wiki et Javadoc que la réponse des liens vers d',Authenticator
's utilisation prévue cas semble être le défi à base d'authentification (tels que l'Authentification Basique, etc.) là où vous vous attendez à plusieurs reprises bosse dans 401 premier, avant la construction de votre en-tête d'autorisation basé sur les régimes/royaumes qui ont été véhiculées par la 401. [TBC]Authenticator
ne semble pas se prêter à la situation où vous avez une constante prédéterminée jeton d'autorisation a une durée de vie s'étendant sur plusieurs demandes (par exemple, jeton OAuth, ou n'importe quel jeton avec n'importe quel type de TTL). J'ai donc fait un Intercepteur, parce que si cela était fait dans leAuthenticator
, il serait inutile 401s a d'abord répondu à chaque demande. Donc, mon approche (qui a été mentionné ci-dessus) est pourInterceptor
pour effectuer jeton d'injection et de laAuthenticator
seul rôle est de détecter jeton d'expiration ou de la révocation.SyncAdapter
+AccountManager
. Donc, monAuthenticator
est très simple: Si sa fonction de rappel est appelée, elle en informeAccountManager
pour invalider le jeton qu'il détient. Cela conduit àAccountManager
de demander à monAuthenticator
pour obtenir un nouveau jeton... à qui il ne de partir de l'existant Rénovation/OKHttp instance. Vous pourriez peut-être obtenir le même à l'aide d'un global / instance du Singleton de tenir le client, si vous ne l'utilisez pasAccount
s. Essentiellement, comment l'Authenticator
conduit finalement à la même OkHttp exemple utilisé pour actualiser le jeton est juste une programmation architecture défi.Si vous utilisez Rénovation >=
1.9.0
alors vous pouvez faire usage de OkHttp de l' nouveau Intercepteur, qui a été introduit dansOkHttp 2.2.0
. Vous souhaitez utiliser un Application De L'Intercepteur, qui vous permet d'retry and make multiple calls
.Votre Intercepteur pourrait ressembler à quelque chose comme ce pseudo-code:
Après vous définissez votre
Interceptor
, créer unOkHttpClient
et ajouter de l'intercepteur comme un Application De L'Intercepteur.Et enfin, l'utilisation de cette
OkHttpClient
lors de la création de votreRestAdapter
.Avertissement: Comme
Jesse Wilson
(de la Place) mentionne ici, c'est une quantité dangereuse de puissance.Avec cela étant dit, je crois vraiment que c'est la meilleure façon de gérer quelque chose comme cela maintenant. Si vous avez des questions, n'hésitez pas à demander dans un commentaire.
Si vous avez, disons, une Rénovation
TokenService
que vous avez besoin à l'intérieur de votreAuthenticator
mais seulement comme unOkHttpClient
vous pouvez utiliser unTokenServiceHolder
comme une dépendance deTokenAuthenticator
. Vous devez conserver une référence à l'application (singleton) niveau. C'est facile si vous êtes à l'aide de la Dague à 2, sinon, il suffit de créer une classe de terrain à l'intérieur de votre Application.Dans
TokenAuthenticator.java
Dans
TokenServiceHolder.java
:L'installation du Client:
Si vous êtes à l'aide de la Dague à 2 ou similaire à celle de l'injection de dépendances cadre il y a quelques exemples dans les réponses aux cette question
TokenService
classe créée?refreshToken()
deservice.refreshToken().execute();
. Pas en mesure de trouver, c'est la mise en œuvre n'importe où.À l'aide de
TokenAuthenticator
comme @theblang réponse est une bonne façon de gérerrefresh_token
.Voici mon œuvre (j'ai l'aide de Kotlin, Dague, RX, mais vous pouvez utiliser cette idée pour l'appliquer à votre cas)
TokenAuthenticator
Pour prévenir cycle de dépendance comme @Brais Gabin commentaire, j'ai créer 2 interface comme
et
AccessTokenWrapper
classeAccessToken
classeMon Intercepteur
Enfin, ajouter
Interceptor
etAuthenticator
à votreOKHttpClient
lors de la création d'un service PotoAuthApiDémo
https://github.com/PhanVanLinh/AndroidMVPKotlin
Remarque
Authentificateur de flux de
getImage()
retour code d'erreur 401authenticate
méthode à l'intérieur d'TokenAuthenticator
sera tirénoneAuthAPI.refreshToken(...)
appelénoneAuthAPI.refreshToken(...)
response -> nouveau jeton va ajouter à l'en-têtegetImage()
sera AUTOMATIQUE appelé avec nouvel en-tête (HttpLogging
ne SERA PAS le journal cet appel) (intercept
à l'intérieur deAuthInterceptor
ne SERA PAS APPELÉ)Si
getImage()
encore a échoué avec l'erreur 401,authenticate
méthode à l'intérieur d'TokenAuthenticator
sera tiré ENCORE et ENCORE alors qu'il va jeter erreur sur l'appel de la méthode beaucoup de temps(java.net.ProtocolException: Too many follow-up requests
). Vous pouvez l'empêcher en le comte de réponse. Exemple, si vousreturn null
dansauthenticate
au bout de 3 fois réessayer,getImage()
sera finition etreturn response 401
Si
getImage()
réponse réussite => nous allons résultat le résultat normalement (comme vous l'appelezgetImage()
sans erreur)Espoir aide
Je sais que ce un vieux thread, mais juste au cas où quelqu'un a trébuché en elle.
J'ai été confrontée au même problème, mais je voulais créer un seul OkHttpClient parce que je ne pense pas que j'ai besoin d'un autre pour tout le TokenAuthenticator lui-même, j'ai été en utilisant Dagger2, j'ai donc fini par fournir le service de classe comme Paresseux injecté dans le TokenAuthenticator, vous pouvez en lire plus à propos de Paresseux injection dans dague 2 ici, mais c'est comme le dit essentiellement à la Dague, à PAS aller et de créer le service requis par la TokenAuthenticator tout de suite.
Vous pouvez vous référer à ce fil pour un exemple de code: Comment résoudre une dépendance circulaire, tout en utilisant Dagger2?
Vous pouvez essayer de créer une classe de base pour tous vos chargeurs dans laquelle vous serez capable d'attraper une exception particulière et d'agir comme vous en avez besoin.
Faites tous vos différents chargeurs d'étendre à partir de la classe de base dans le but de répandre le comportement.
OkHttp
avec de Rénovation, vous pouvez faire usage de la nouvelle Intercepteur API pour faire quelque chose comme cela.Après de Longues recherches, je l'ai adapté Apache client pour gérer Rafraîchissante AccessToken De Rénovation Dans lequel vous envoyer jeton d'accès en tant que paramètre.
Lancer votre Carte avec cookie Persistant Client
Cookie Persistant client qui gère les cookies pour toutes les demandes et vérifie à chaque demande de réponse, si c'est un accès non autorisé CODE_ERREUR = 401, actualiser jeton d'accès et de rappel de la demande, d'autre juste processus de demande.
L'aide d'un Intercepteur (injecter le jeton) et un Authentificateur (opérations d'actualisation) faire le travail, mais:
J'ai eu un double appel de problème aussi: le premier appel toujours retourné 401:
le jeton n'était pas injecter au premier appel (intercepteur) et l'authentificateur a été appelé: deux demandes ont été faites.
Le correctif était juste pour reaffect la demande pour la construction de l'Intercepteur:
AVANT:
APRÈS:
DANS UN BLOC:
Espère que cela aide.
Edit: je n'ai pas trouver un moyen d'éviter le premier appel à la revenant toujours 401 en utilisant uniquement l'authentificateur et aucun intercepteur
À tous ceux qui voulaient résoudre simultanée/parallèle des appels lors de l'actualisation de jeton. Voici une solution de contournement