Nous utilisons Retrofit dans notre application Android pour communiquer avec un serveur sécurisé OAuth2. Tout fonctionne à merveille, nous utilisons RequestInterceptor pour inclure le jeton d'accès à chaque appel. Cependant, il y aura des moments où le jeton d'accès expirera et le jeton doit être actualisé. Lorsque le jeton expire, le prochain appel sera renvoyé avec un code HTTP non autorisé, ce qui est facile à surveiller. Nous pourrions modifier chaque appel Retrofit de la manière suivante: dans le rappel d'échec, vérifiez le code d'erreur, s'il est égal à Non autorisé, actualisez le jeton OAuth, puis répétez l'appel Retrofit. Cependant, pour cela, tous les appels doivent être modifiés, ce qui n'est pas une solution facilement maintenable et bonne. Existe-t-il un moyen de le faire sans modifier tous les appels de retrofit?
157
Réponses:
Veuillez ne pas utiliser
Interceptors
pour traiter l'authentification.Actuellement, la meilleure approche pour gérer l'authentification consiste à utiliser la nouvelle
Authenticator
API, conçue spécifiquement à cet effet .OkHttp demandera automatiquement les
Authenticator
informations d'identification lorsqu'une réponse401 Not Authorised
réessaye la dernière demande ayant échoué avec eux.Attachez un
Authenticator
à unOkHttpClient
comme vous le faites avecInterceptors
Utilisez ce client lors de la création de votre
Retrofit
RestAdapter
la source
TokenAuthenticator
dépend d'uneservice
classe. Laservice
classe dépend d'uneOkHttpClient
instance. Pour créer unOkHttpClient
j'ai besoin du fichierTokenAuthenticator
. Comment puis-je briser ce cycle? DeuxOkHttpClient
s différents ? Ils vont avoir différents pools de connexion ...Si vous utilisez Retrofit > =,
1.9.0
vous pouvez utiliser le nouvel intercepteur d' OkHttp , qui a été introduit dansOkHttp 2.2.0
. Vous souhaitez utiliser un intercepteur d'application , ce qui vous permet de le faireretry and make multiple calls
.Votre intercepteur pourrait ressembler à quelque chose comme ce pseudocode:
Après avoir défini votre
Interceptor
, créez unOkHttpClient
et ajoutez l'intercepteur en tant qu'intercepteur d' application .Et enfin, utilisez ceci
OkHttpClient
lors de la création de votre fichierRestAdapter
.Attention: comme
Jesse Wilson
(de Square) le mentionne ici , il s'agit d'une quantité d'énergie dangereuse.Cela étant dit, je pense définitivement que c'est la meilleure façon de gérer quelque chose comme ça maintenant. Si vous avez des questions, n'hésitez pas à les poser dans un commentaire.
la source
Si vous avez, par exemple, un Retrofit
TokenService
dont vous avez besoin à l'intérieur de votreAuthenticator
mais que vous ne souhaitez en installer qu'un pour lequelOkHttpClient
vous pouvez utiliser aTokenServiceHolder
comme dépendanceTokenAuthenticator
. Vous devrez en conserver une référence au niveau de l'application (singleton). C'est facile si vous utilisez Dagger 2, sinon créez simplement un champ de classe dans votre application.Dans
TokenAuthenticator.java
Dans
TokenServiceHolder.java
:Configuration du client:
Si vous utilisez Dagger 2 ou un framework d'injection de dépendances similaire, il y a quelques exemples dans les réponses à cette question
la source
TokenService
classe est -elle créée?refreshToken()
deservice.refreshToken().execute();
. Impossible de trouver sa mise en œuvre nulle part.Utiliser
TokenAuthenticator
une réponse comme @theblang est une manière correcte de gérerrefresh_token
.Voici mon outil (j'utilise Kotlin, Dagger, RX mais vous pouvez utiliser cette idée pour implémenter votre cas)
TokenAuthenticator
Pour éviter le cycle de dépendance comme le commentaire @Brais Gabin, je crée 2 interfaces comme
et
AccessTokenWrapper
classeAccessToken
classeMon intercepteur
Enfin, ajoutez
Interceptor
etAuthenticator
à votreOKHttpClient
lors de la création du service PotoAuthApiDémo
https://github.com/PhanVanLinh/AndroidMVPKotlin
Remarque
Flux d'authentificateurgetImage()
code d'erreur de retour d' API 401authenticate
la méthode à l'intérieurTokenAuthenticator
sera tiréenoneAuthAPI.refreshToken(...)
appelénoneAuthAPI.refreshToken(...)
réponse -> un nouveau jeton s'ajoutera à l'en-têtegetImage()
sera AUTO appelé avec un nouvel en-tête (HttpLogging
ne journalisera pas cet appel) (à l'intercept
intérieurAuthInterceptor
ne sera pas appelé )Si
getImage()
toujours échoué avec l'erreur 401, laauthenticate
méthode à l'intérieurTokenAuthenticator
sera déclenchée à NOUVEAU et à NOUVEAU, puis elle lancera une erreur sur la méthode d'appel plusieurs fois (java.net.ProtocolException: Too many follow-up requests
). Vous pouvez l'empêcher en comptant la réponse . Par exemple, si vousreturn null
enauthenticate
après 3 fois nouvelle tentative,getImage()
va finir etreturn response 401
Si
getImage()
réponse réussie => nous obtiendrons le résultat normalement (comme vous appelezgetImage()
sans erreur)J'espère que ça aide
la source
Je sais que c'est un vieux fil, mais juste au cas où quelqu'un y trébucherait.
J'étais confronté au même problème, mais je voulais créer un seul OkHttpClient car je ne pense pas que j'en ai besoin d'un autre uniquement pour le TokenAuthenticator lui-même, j'utilisais Dagger2, donc j'ai fini par fournir la classe de service comme Lazy injecté dans le TokenAuthenticator, vous pouvez en savoir plus sur l'injection Lazy dans dagger 2 ici , mais c'est comme dire à Dagger de NE PAS créer le service nécessaire au TokenAuthenticator tout de suite.
Vous pouvez vous référer à ce thread SO pour un exemple de code: Comment résoudre une dépendance circulaire tout en utilisant Dagger2?
la source
Vous pouvez essayer de créer une classe de base pour tous vos chargeurs dans laquelle vous seriez en mesure d'attraper une exception particulière, puis d'agir selon vos besoins. Faites en sorte que tous vos différents chargeurs s'étendent à partir de la classe de base afin de diffuser le comportement.
la source
Après de longues recherches, j'ai personnalisé le client Apache pour gérer l'actualisation d'AccessToken pour la modernisation dans lequel vous envoyez un jeton d'accès en tant que paramètre.
Initiez votre adaptateur avec un client persistant de cookie
Cookie Client persistant qui conserve les cookies pour toutes les demandes et vérifie à chaque réponse de demande, s'il s'agit d'un accès non autorisé ERROR_CODE = 401, actualise le jeton d'accès et rappelle la demande, sinon traite simplement la demande.
la source
L'utilisation d'un intercepteur (injecter le jeton) et d'un authentificateur (opérations d'actualisation) fait le travail mais:
J'avais aussi un problème de double appel: le premier appel retournait toujours un 401 : le token n'était pas injecté au premier appel (intercepteur) et l'authentificateur était appelé: deux requêtes étaient faites.
Le correctif consistait simplement à réaffecter la demande à la construction dans l'Interceptor:
AVANT:
APRÈS:
EN UN BLOC:
J'espère que ça aide.
Edit: Je n'ai pas trouvé de moyen d'éviter le premier appel de toujours renvoyer 401 en utilisant uniquement l'authentificateur et aucun intercepteur
la source
À tous ceux qui voulaient résoudre des appels simultanés / parallèles lors de l'actualisation du jeton. Voici une solution de contournement
la source