Le plug-in jwt-logout utilise Redis pour mettre en œuvre une gestion d'état faible des jetons Web JSON (JWT), permettant l'invalidation proactive des JWT et le contrôle de la connexion à partir d'un seul appareil. Par exemple, lorsqu'un utilisateur se connecte depuis un nouvel appareil, la session précédente est automatiquement invalidée.
Type de plug-in
Plug-in dédié à l'authentification et à l'autorisation.
Champs
|
Champ |
Type de données |
Obligatoire |
Valeur par défaut |
Description |
|
jwks |
string |
Non |
- |
Chaîne JSON utilisée pour la vérification des JWT. Ce champ n'est pas requis lorsque ce plug-in est utilisé conjointement avec le plug-in jwt-auth. Pour plus d'informations, consultez la spécification JSON Web Key (JWK). |
|
clock_skew |
number |
Non |
60 |
Décalage horaire autorisé lors de la vérification des champs exp et iat d'un JWT. Unité : secondes. |
|
token_header |
string |
Non |
Authorization |
En-tête de requête à partir duquel le JWT est extrait. |
|
token_prefix |
string |
Non |
"Bearer" |
Préfixe de la valeur de l'en-tête. Une fois le préfixe supprimé, la partie restante est utilisée comme JWT. |
|
redis |
Redis |
Oui |
- |
Configuration du service Redis. |
|
logout |
Logout |
Non |
- |
Configuration de la fonctionnalité de déconnexion JWT. Si cette configuration est absente, la déconnexion JWT est désactivée. |
|
login |
Login |
Non |
- |
Configuration de la fonctionnalité de connexion unique par appareil via JWT. Si cette configuration est absente, la connexion unique par appareil est désactivée. |
Le tableau suivant décrit les champs de configuration du type Redis.
|
Champ |
Type de données |
Obligatoire |
Valeur par défaut |
Description |
|
service |
string |
Oui |
- |
Nom du service Redis. Exemples :
|
|
port |
number |
Oui |
- |
Numéro de port du service Redis. |
|
username |
string |
Non |
- |
Nom d'utilisateur pour la commande Redis AUTH. |
|
password |
string |
Non |
- |
Mot de passe pour la commande Redis AUTH. |
|
timeout |
number |
Non |
1000 |
Délai d'expiration pour les commandes Redis. Unité : millisecondes. |
Le tableau suivant décrit les champs de configuration du type Logout.
|
Champ |
Type de données |
Obligatoire |
Valeur par défaut |
Description |
|
key_prefix |
string |
Non |
higress_jwt_logout_ |
Préfixe de la clé stockée dans Redis. |
|
key |
array of string |
Non |
["jti"] |
Clé présente dans le corps (payload) du JWT qui permet d'identifier un jeton. Si la même clé apparaît dans plusieurs corps de JWT, ces jetons sont considérés comme identiques. Si la clé est absente du corps du JWT, une erreur 401 « invalid token » est renvoyée. |
|
path |
string |
Non |
/jwt_logout |
Chaîne utilisée pour faire correspondre le suffixe du chemin d'URL. En cas de correspondance, le JWT de la requête actuelle est invalidé et ne peut plus être utilisé. |
|
error_status |
number |
Non |
401 |
Code d'état HTTP renvoyé lorsqu'un JWT déconnecté est utilisé. |
|
error_body |
string |
Non |
'{"message":"invalid token"}' |
Corps de la réponse renvoyé lorsqu'un JWT déconnecté est utilisé. |
|
ttl |
number |
Non |
- |
Durée de vie (TTL) de la clé stockée dans Redis. Unité : secondes. Détermine la durée pendant laquelle le JWT reste invalidé après la déconnexion. Si non spécifié, la TTL correspond à la valeur du champ exp du corps moins l'heure actuelle. Si le corps ne contient pas le champ exp, la TTL par défaut est de 86 400 secondes (24 heures). |
Le tableau suivant décrit les champs de configuration du type Login.
|
Champ |
Type de données |
Obligatoire |
Valeur par défaut |
Description |
|
key_prefix |
string |
Non |
higress_jwt_logout_ |
Préfixe de la clé stockée dans Redis. |
|
key |
array of string |
Non |
["iss","aud","sub"] |
Identifiant de connexion unique par appareil dans le corps du JWT. Si le JWT de la requête actuelle contient les mêmes valeurs de champ qu'un JWT précédemment authentifié, mais qu'il ne s'agit pas exactement du même jeton, la requête est rejetée en tant que double connexion. L'accès est refusé jusqu'à l'expiration de la clé Redis associée au JWT authentifié. Si le champ est absent du corps du JWT, une erreur 401 « invalid token » est renvoyée. |
|
path |
string |
Non |
/jwt_login |
Chaîne utilisée pour faire correspondre le suffixe du chemin d'URL. En cas de correspondance, le JWT de la requête actuelle devient le jeton de session actif et tout JWT précédemment authentifié présentant les mêmes caractéristiques de corps est invalidé. |
|
error_status |
number |
Non |
403 |
Code d'état HTTP renvoyé en cas de tentative de double connexion. |
|
error_body |
string |
Non |
'{"message":"already login on other device"}' |
Corps de la réponse renvoyé en cas de tentative de double connexion. |
|
ttl |
number |
Non |
- |
Durée de vie (TTL) de la clé stockée dans Redis. Unité : secondes. Détermine la période de validité d'un JWT pour la connexion unique par appareil. Si non spécifié, la TTL correspond à la valeur du champ exp du corps moins l'heure actuelle. Si le corps ne contient pas le champ exp, la TTL par défaut est de 86 400 secondes (24 heures). |
Exemples de configuration
Utiliser une instance ApsaraDB for Redis
Créez une instance ApsaraDB for Redis. Pour plus d'informations, consultez la rubrique Présentation.
Activez les configurations de déconnexion et de connexion. Lorsque le plug-in traite une requête, il effectue une lecture Redis pour vérifier la configuration de déconnexion et deux lectures Redis pour vérifier la configuration de connexion. Dans de rares cas, tels qu'une déconnexion ou une première connexion, deux écritures Redis supplémentaires sont générées. Pour estimer la capacité de l'instance ApsaraDB for Redis, multipliez le débit des requêtes traitées par le plug-in par 2.
Après avoir configuré l'instance ApsaraDB for Redis, récupérez le point de terminaison VPC de l'instance. Exemple : r-xxxxxxx.redis.rds.aliyuncs.com.
Ajoutez un service. Sélectionnez DNS Domain Name dans la liste déroulante Service Source, saisissez le numéro de port Redis (généralement 6379) dans le champ Service Port, entrez le point de terminaison VPC dans le champ Domain Names et sélectionnez Disabled dans la liste déroulante TLS Mode. Pour plus d'informations, consultez la rubrique Créer un service.
-
Ajoutez le contenu suivant à la configuration du plug-in pour vous connecter à l'instance ApsaraDB for Redis :
redis: service: redis.dns port: 6379Si vous configurez un mot de passe pour le service Redis, ajoutez le contenu suivant :
redis: service: redis.dns port: 6379 password: ****** # Enter the password that you specify.
Mettre en œuvre la fonctionnalité de déconnexion JWT
Cas d'utilisation
Les JWT sont des jetons sans état qui restent valides jusqu'à leur expiration. Utilisez le plug-in jwt-logout pour invalider de force un JWT spécifique avant son expiration.
Fonctionnement
Si le suffixe du chemin de la requête correspond au chemin défini dans la configuration du plug-in, le mécanisme de déconnexion est déclenché. L'instance ApsaraDB for Redis enregistre le JWT pour la déconnexion. La clé stockée dans l'instance ApsaraDB for Redis se compose du préfixe configuré ainsi que de la clé et de la valeur extraites du corps du JWT actuel.
Si le corps du JWT transmis dans la requête correspond aux caractéristiques de la clé stockée dans l'instance ApsaraDB for Redis, le système considère le JWT actuel comme invalide et rejette la requête.
L'heure d'expiration par défaut de la clé stockée dans l'instance ApsaraDB for Redis est calculée sur la base du champ
expprésent dans le corps du JWT. Cela signifie que la clé peut être conservée jusqu'à l'expiration du JWT.
La clé de déconnexion recommandée par défaut pour le plug-in est ["jti"], où
jtiest le champ du corps qui identifie de manière unique un JWT. Conformément aux normes JWT, si la valeurjtidans le corps du JWT est identique à celle enregistrée dans l'instance ApsaraDB for Redis, le JWT entier est exactement le même. Par conséquent, jti peut être utilisé pour marquer l'état de déconnexion d'un JWT.Règle de concaténation de la clé stockée dans l'instance ApsaraDB for Redis :
<key_prefix><PayloadKey>##<PayloadValue>. PayloadKey est une liste de clés délimitées par des dièses (#). PayloadValue est une liste de valeurs de clés délimitées par des dièses (#). Exemple :higress_jwt_logout_jti#iss##xxxxx#abcde.Ce plug-in ne peut invalider que le jeton transmis dans la requête actuelle lors de la déconnexion. Vous pouvez également spécifier manuellement le jeton dans la console ApsaraDB for Redis en suivant la règle de concaténation de clé décrite ci-dessus. Si la passerelle détecte que la clé existe dans l'instance ApsaraDB for Redis, elle rejette la demande d'accès basée sur le JWT concerné.
Exemple
Configuration du plug-in :
redis:
service: redis.dns
port: 6379
jwks: |
{
"keys": [
{
"kty": "oct",
"kid": "123",
"k": "hM0k3AbXBPpKOGg__Ql2Obcq7s60myWDpbHXzgKUQdYo7YCRp0gUqkCnbGSvZ2rGEl4YFkKqIqW7mTHdj-bcqXpNr-NOznEyMpVPOIlqG_NWVC3dydBgcsIZIdD-MR2AQceEaxriPA_VmiUCwfwL2Bhs6_i7eolXoY11EapLQtutz0BV6ZxQQ4dYUmct--7PLNb4BWJyQeWu0QfbIthnvhYllyl2dgeLTEJT58wzFz5HeNMNz8ohY5K0XaKAe5cepryqoXLhA-V-O1OjSG8lCNdKS09OY6O0fkyweKEtuDfien5tHHSsHXoAxYEHPFcSRL4bFPLZ0orTt1_4zpyfew",
"alg": "HS256"
}
]
}
logout:
path: "/jwt_logout"
key: ["jti"]
error_status: 401
error_body: |
{"message":"invalid token"}
-
Déclenchez une déconnexion.
curl http://xxx.hello.com/test/jwt_logout -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJ4eHh4IiwiaXNzIjoiYWJjZCIsInN1YiI6InRlc3QiLCJhdWQiOiJ3d3cudGVzdC5jb20iLCJpYXQiOjE2NjU2NjA1MjcsImV4cCI6MTg2NTY3MzgxOX0.tmKF6qc1mOWNyCCzBOT2XKNoEGeEgr3EbhTKAQfq1io' # The following result is returned: {"message": "logout success"}Corps du jeton :
{ "jti": "xxxx", "iss": "abcd", "sub": "test", "aud": "www.test.com", "iat": 1665660527, "exp": 1865673819 }Dans ce cas, la clé
higress_jwt_logout_jti##xxxxest stockée dans l'instance ApsaraDB for Redis. -
Après la déconnexion, l'accès basé sur le JWT n'est pas autorisé.
curl http://xxx.hello.com/test/abc -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJ4eHh4IiwiaXNzIjoiYWJjZCIsInN1YiI6InRlc3QiLCJhdWQiOiJ3d3cudGVzdC5jb20iLCJpYXQiOjE2NjU2NjA1MjcsImV4cCI6MTg2NTY3MzgxOX0.tmKF6qc1mOWNyCCzBOT2XKNoEGeEgr3EbhTKAQfq1io' # The following result is returned: {"message":"invalid token"}
Mettre en œuvre une déconnexion forcée basée sur les JWT
Cas d'utilisation
Lorsqu'un compte se connecte depuis plusieurs appareils avec une authentification JWT, différents JWT peuvent être émis pour chaque appareil. Utilisez le plug-in jwt-logout pour imposer une connexion unique par appareil, afin qu'une seule session reste active à la fois.
Fonctionnement
Lorsqu'une requête est initiée, le système extrait le JWT de la requête actuelle et constitue une clé Redis basée sur le préfixe configuré ainsi que sur la clé et la valeur extraites du corps du JWT actuel. Ensuite, le système interroge la valeur correspondant à la clé dans l'instance ApsaraDB for Redis. Si la valeur est incohérente avec la valeur de clé du JWT actuel, le système rejette la demande d'accès.
Si la valeur n'existe pas, le JWT actuel est écrit dans la clé Redis. L'heure d'expiration par défaut de la clé dans l'instance ApsaraDB for Redis est calculée sur la base du champ
expprésent dans le corps du JWT. Cela signifie que la clé peut être conservée jusqu'à l'expiration du JWT. Pendant la période de validité du JWT, les demandes d'accès basées sur d'autres JWT présentant les mêmes caractéristiques de corps ne sont pas autorisées.Si le suffixe de la requête correspond au
pathdéfini dans la configuration du plug-in, le mécanisme de déconnexion forcée est déclenché et le JWT actuel est écrit dans la valeur de la clé Redis associée. Le JWT utilisé pour une connexion réussie et présentant les mêmes caractéristiques de corps est invalidé lors de la déconnexion. Cela garantit une connexion unique par appareil.
La clé de connexion recommandée par défaut pour le plug-in est ["iss","aud","sub"]. Dans cette clé,
issindique l'émetteur du JWT,audindique le scénario d'utilisation du JWT etsubindique le sujet du JWT. Dans la plupart des cas, cette combinaison permet de garantir une connexion unique par appareil.Règle de concaténation de la clé stockée dans l'instance ApsaraDB for Redis :
<key_prefix><PayloadKey>##<PayloadValue>. PayloadKey est une liste de clés délimitées par des dièses (#). PayloadValue est une liste de valeurs de clés délimitées par des dièses (#). Exemple :higress_jwt_login_iss#aud#sub##xxxxx#abcde#fffff.Pour les JWT présentant les mêmes caractéristiques de corps, le premier JWT utilisé pour les requêtes est automatiquement écrit dans l'instance ApsaraDB for Redis. Cela permet de mettre en œuvre la fonctionnalité de connexion unique par appareil du plug-in. Par conséquent, vous n'avez pas besoin d'appeler l'opération API pour une connexion forcée. Vous devez appeler l'opération API uniquement lorsqu'une déconnexion forcée est requise dans les scénarios de connexion.
Lorsque vous déclenchez la logique de déconnexion, la clé de connexion du JWT actuel stockée dans l'instance ApsaraDB for Redis est effacée. Cette règle s'applique également lorsque vous activez la fonctionnalité de déconnexion JWT.
Exemple
Configuration du plug-in :
redis:
service: redis.dns
port: 6379
jwks: |
{
"keys": [
{
"kty": "oct",
"kid": "123",
"k": "hM0k3AbXBPpKOGg__Ql2Obcq7s60myWDpbHXzgKUQdYo7YCRp0gUqkCnbGSvZ2rGEl4YFkKqIqW7mTHdj-bcqXpNr-NOznEyMpVPOIlqG_NWVC3dydBgcsIZIdD-MR2AQceEaxriPA_VmiUCwfwL2Bhs6_i7eolXoY11EapLQtutz0BV6ZxQQ4dYUmct--7PLNb4BWJyQeWu0QfbIthnvhYllyl2dgeLTEJT58wzFz5HeNMNz8ohY5K0XaKAe5cepryqoXLhA-V-O1OjSG8lCNdKS09OY6O0fkyweKEtuDfien5tHHSsHXoAxYEHPFcSRL4bFPLZ0orTt1_4zpyfew",
"alg": "HS256"
}
]
}
login:
path: "/jwt_login"
key: ["iss","aud","sub"]
error_status: 403
error_body: |
{"message":"already login on other device"}
-
Effectuez une opération de connexion réussie.
curl http://xxx.hello.com/test/abc -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJ6enp6IiwiaXNzIjoiYWJjZCIsImF1ZCI6Ind3dy5leGFtcGxlLmNvbSIsInN1YiI6InRlc3QiLCJpYXQiOjE2NjU2NjA1MjcsImV4cCI6MTg2NTY3MzgxOX0.WljMr5ucxfLF8SmeaaL25c0QG3IX04HoD0als9gglYg'Corps du jeton :
{ "jti": "zzzz", "iss": "abcd", "aud": "www.example.com", "sub": "test", "iat": 1665660527, "exp": 1865673819 }Dans ce cas, la clé
higress_jwt_login_iss#aud#sub##abcd#www.example.com#abcdest stockée dans l'instance ApsaraDB for Redis et la valeur est identique à celle du JWT actuel. -
Rejetez une demande d'accès lorsque le corps du JWT dans la requête présente les mêmes caractéristiques.
curl http://xxx.hello.com/test/abc -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJqdGkiOiJ5eXl5eSIsImlzcyI6ImFiY2QiLCJhdWQiOiJ3d3cuZXhhbXBsZS5jb20iLCJzdWIiOiJ0ZXN0IiwiaWF0IjoxNjY1NjYwNTI5LCJleHAiOjE4NjU2NzM4MTl9.6vi6eKPWSKHQxfzBPrj3-SWI4Q5zGtWhqp38JIN3FEo' # The following result is returned: {"message":"already login on other device"}Corps du jeton :
{ "jti": "yyyyy", "iss": "abcd", "aud": "www.example.com", "sub": "test", "iat": 1665660527, "exp": 1865673819 }Les caractéristiques du corps sont identiques pour le JWT actuel et le JWT de l'étape 1. Cependant, le champ non caractéristique
jtidiffère entre les deux JWT. Par conséquent, la demande d'accès basée sur le JWT est rejetée. -
Effectuez une connexion forcée.
curl http://xxx.hello.com/test/jwt_login -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJqdGkiOiJ5eXl5eSIsImlzcyI6ImFiY2QiLCJhdWQiOiJ3d3cuZXhhbXBsZS5jb20iLCJzdWIiOiJ0ZXN0IiwiaWF0IjoxNjY1NjYwNTI5LCJleHAiOjE4NjU2NzM4MTl9.6vi6eKPWSKHQxfzBPrj3-SWI4Q5zGtWhqp38JIN3FEo' # The following result is returned: {"message":"login success"}Dans ce cas, la clé
higress_jwt_login_iss#aud#sub##abcd#www.example.com#abcdest stockée dans l'instance ApsaraDB for Redis et la valeur est remplacée par celle du JWT actuel.Utilisez le JWT actuel pour accéder avec succès à la page.
curl http://xxx.hello.com/test/abc -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJqdGkiOiJ5eXl5eSIsImlzcyI6ImFiY2QiLCJhdWQiOiJ3d3cuZXhhbXBsZS5jb20iLCJzdWIiOiJ0ZXN0IiwiaWF0IjoxNjY1NjYwNTI5LCJleHAiOjE4NjU2NzM4MTl9.6vi6eKPWSKHQxfzBPrj3-SWI4Q5zGtWhqp38JIN3FEo'Si vous utilisez le JWT de l'étape 1, un message d'échec est renvoyé.
curl http://xxx.hello.com/test/abc -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJqdGkiOiJ4eHh4IiwiaXNzIjoiYWJjZCIsImF1ZCI6Ind3dy5leGFtcGxlLmNvbSIsInN1YiI6InRlc3QiLCJpYXQiOjE2NjU2NjA1MjcsImV4cCI6MTg2NTY3MzgxOX0.P0WtBTHJzUJvklu9q8XSRszfPbgojrZHg7t4ZaYfKGo' # The following result is returned: {"message":"already login on other device"}
Codes d'erreur
|
Code d'état HTTP |
Message d'erreur |
Raison |
|
401 |
invalid token |
Aucun JWT n'est fourni dans l'en-tête de la requête, le format du JWT est invalide, ou le JWT a expiré ou a été invalidé. |
|
500 |
redis server error |
L'instance ApsaraDB for Redis est inaccessible ou la connexion a expiré. |