J'écris un client REST en Java à l'aide de HttpCLient, l'API REST à laquelle j'ai accès nécessite un jeton d'authentification pour chaque action REST. Ce jeton est valable 24 heures.
Je gère maintenant cette situation en appelant une méthode "getAuth()
" à chaque fois que je dois passer un appel REST, ce qui semble être une surcharge pour le serveur d'authentification.
Comment puis-je facilement stocker ce jeton d'authentification et gérer son cycle de vie? Existe-t-il des meilleures pratiques documentées?
J'ai pensé à la solution suivante
public class MySession {
String user;
String pass;
public MySession(String user, String pass) {
this.user = user;
this.pass = pass;
}
public getAuth() {
//user user, pass to get auth token
}
}
puis passez l'objet sessions à n'importe quelle classe qui n'a pas le jeton. Si le jeton a expiré, appelez simplement cette méthode à nouveau.
Par souci de brièveté, je suppose que vous appelez un point d'extrémité que vous ne pouvez pas modifier. La manière dont vous devez implémenter dépend fortement du type de jeton utilisé (application ou utilisateur) (un jeton pour tous les utilisateurs d'une instance d'application partagée ou un jeton par utilisateur).
S'il s'agit d'un jeton d'authentification pour l'ensemble de l'application:
S'il s'agit d'un jeton par utilisateur:
Je suppose que vous utilisez OAuth pour obtenir une autorisation. Que vous utilisiez JWT ou d'autres jetons n'est pas pertinent dans cette situation.
Lors de l'exécution de l'autorisation, vous recevrez un access_token
avec une expiration et, en fonction du type d'octroi que vous demandez (informations d'identification du client, code d'autorisation, implicite, propriétaire de la ressource), un refresh_token
.
Le client doit conserver le access_token
et l'expiration. La valeur refresh_token, si elle est publiée, doit être gardée secrète (méfiez-vous de l'utilisation de la subvention appropriée pour votre cas d'utilisation).
Lors des appels suivants, votre client ne doit pas demander de nouveaux jetons à chaque appel, il doit utiliser le access_token
stocké.
Une fois que l'API commence à renvoyer 401 Unauthorized
, le access_token
a probablement expiré. Votre client doit essayer d'actualiser le access_token
à l'aide du refresh_token
si vous en avez un.
Si vous n'avez pas de refresh_token
ou si la demande d'actualisation a également échoué, car le refresh_token
n'est plus valide, vous pouvez effectuer un nouveau flux d'autorisation.
Vous pouvez utiliser l’heure d’expiration comme indice pour savoir quand obtenir un nouveau access_token
par le biais d’une actualisation ou d’un nouveau flux d’autorisation complet. Cela évitera le 401 Unauthorized
. Dans tous les cas, votre client devrait avoir une politique de secours lorsque cette réponse est reçue après avoir utilisé un access_token
valide pour certains appels.
Si vous vous inquiétez du trop grand nombre de hits dans la base de données, je suppose qu'il y a beaucoup d'activité sur le Web.
Je ne recommanderais pas d'utiliser Session dans votre cas, mais plutôt de stocker le jeton dans un cookie sur le client.
Dans un environnement à fort trafic (ce qui, je suppose, est le vôtre), l'utilisation de Session peut consommer beaucoup de mémoire serveur et l'évolutivité peut également être un problème, car vous devez maintenir les sessions synchronisées dans un cluster.
Comme @ Cássio Mazzochi Molin l'a également mentionné, vous pouvez utiliser un cache en mémoire pour stocker des données et des jetons spécifiques à un utilisateur. Cela réduira le nombre d'occurrences dans la base de données et vous permettra également de faire évoluer l'application plus facilement, le cas échéant.
Je vous suggère d'utiliser le scénario suivant:
1) Commencez par appeler auth(username, password)
api rest pour obtenir le jeton d'authentification . Si les informations d'identification fournies sont correctes, envoyez simplement le cookie d'authentification au client avec le code de réponse HTTP 200.
2) Ensuite, vous pouvez appeler des apis protégés. Vous devez envoyer un cookie d’authentification avec votre demande à chaque fois.
3) Le filtre de servlet (ou quelque chose de similaire) vérifie chaque demande entrante et valide le jeton. Si le jeton est valide, la demande est transmise à la méthode reste, sinon vous devez générer une réponse http 401/403.
Je vous suggère de ne pas écrire votre propre couche d'authentification. Au lieu d'installer et d'utiliser un existant. Je vous suggère OpenAM . C'est un superbe système de gestion d'accès open source.
Je vous suggère également de ne pas ouvrir la session côté serveur à des fins d'authentification. Si vous avez 10 clients, 10 sessions doivent être gérées par le serveur. Ce n'est pas un gros problème. Mais si vous avez 100, 1 000 ou des millions de clients différents, vous avez besoin de plus de mémoire pour stocker des sessions sur le serveur.
Vous devriez utiliser JsonWebToken (JWT en bref) pour ce genre de choses. JWT a un support intégré pour définir la date d'expiration. Il existe de nombreuses bibliothèques pour utiliser cette méthode et vous pouvez en lire plus ici
Il existe actuellement 4 implémentations Java et toutes peuvent vérifier si le jeton est toujours valide (vérification exp)
Donc, si je comprends bien, vous utilisez le même jeton pour toutes vos demandes (ce qui signifie que tant que votre application est opérationnelle et que vous actualisez les jetons, vous devriez être d'accord. J'ai littéralement le même problème et c'est J'ai une classe singleton, qui est initialisée au démarrage de l'application pour une fois et actualise le jeton lorsqu'elle est invalidée. J'utilise C #, Asp.NET MVC5 et AutoFac pour DI, mais je suis sûr vous pouvez faire la même chose avec Java et Spring.
Mise à jour de la propriété d'un singleton avec Thread Safety
Vous pouvez créer un gestionnaire et stocker le cookie d'authentification lors de la connexion dans un thread local, comme dans le code ci-dessous. Vous pouvez obtenir le cookie à partir de getAuth()
tant que le thread est en vie.
public class Manager {
private static final ThreadLocal<String> SECURITY_CONTEXT = new ThreadLocal<>();
public static void setAuth(String auth) {
SECURITY_CONTEXT.set(auth);
}
public static String getAuth() {
return SECURITY_CONTEXT.get();
}
public static void clear(){
SECURITY_CONTEXT.remove();
}
}
La norme de facto n’implémente pas votre propre solution (règle de base en sécurité: n’implémentez pas vos propres éléments!), Mais utilisez la solution standard de facto, à savoir JSON Web Tokens .
La documentation sur le site, mais l'idée de base est qu'il ne vous faut que stocker une valeur (la clé privée du serveur), et ensuite vous pouvez vérifier chaque revendication, émise à l'origine par le serveur (qui contiendra dans votre cas un délai d'expiration). .
Utilisez les jetons Web Json pour échanger des informations entre deux clients. Le jeton ne sera actif que pendant la période de 24 heures; après cette heure, tous les appels consécutifs dans l'en-tête seront rejetés.