jwt-logoutプラグインは、Redisを使用してJSON Webトークン (jwt) の弱い状態管理を実装します。 プラグインは、JWTがプロアクティブなログオフをサポートしないという問題を解決します。 プラグインを使用して、アカウントの単一デバイスログオンを実装することもできます。 たとえば、アカウントが別のデバイスにログオンするために使用されると、アカウントはデバイスから自動的にログオフされます。
プラグイン型
認証と承認のためのプラグイン。
フィールド
項目 | データ型 | 必須 / 任意 | デフォルト値 | 説明 |
jwks | String | 非対象 | - | JWTの検証に使用されるJSON文字列。 このプラグインをjwt-authプラグインと一緒に使用する場合、このフィールドを設定する必要はありません。 詳細については、「JSON Webキー (JWK) 」をご参照ください。 |
clock_skew | 数値 | 非対象 | 60 | JWTのexpフィールドとiatフィールドがチェックされるときに許可されるクロックオフセット。 単位は秒です。 |
token_header | String | 非対象 | 承認 | JWTを抽出できるリクエストヘッダー。 |
token_prefix | String | 非対象 | 「ベアラー」 | リクエストヘッダーの値のプレフィックス。 プレフィックスが削除された後、リクエストヘッダーの残りの部分がJWTコンテンツとして使用されます。 |
redis | Redis | 対象 | - | Redisサービスの設定。 |
logout | ログアウト | 非対象 | - | JWTログオフ機能を実装するために使用される設定。 このフィールドが設定されていない場合、JWTログオフ機能は無効になります。 |
login | ログイン | 非対象 | - | JWTシングルデバイスログオン機能を実装するために使用される設定。 このフィールドが設定されていない場合、JWTシングルデバイスログイン機能は無効になります。 |
次の表に、Redisタイプの設定フィールドを示します。
項目 | データ型 | 必須 / 任意 | デフォルト値 | 説明 |
service | String | 対象 | - | Redisサービスの名前。 例:
|
port | 数値 | 対象 | - | Redisサービスのポート番号。 |
username | String | 非対象 | - | Redis AUTHコマンドで使用されるユーザー名。 |
password | String | 非対象 | - | Redis AUTHコマンドで使用されるパスワード。 |
timeout | 数値 | 非対象 | 1000 | Redisコマンドのタイムアウト期間。 単位:ミリ秒。 |
次の表に、ログアウトタイプの設定フィールドを示します。
項目 | データ型 | 必須 / 任意 | デフォルト値 | 説明 |
key_prefix | String | 非対象 | higress_jwt_logout_ | Redisに格納されているキーのプレフィックス。 |
キー | 文字列の配列 | 非対象 | ["jti"] | JWTを識別するためのJWTペイロードのキー。 同じ鍵が複数のJWTのペイロードに含まれている場合、JWTは同じものと見なされる。 キーがJWTペイロードに含まれていない場合、エラー401無効なトークンが報告されます。 |
パス | String | 非対象 | /jwt_logout | URLパスのサフィックスと一致するために使用される文字列。 URLパスサフィックスが指定された文字列と一致する場合、現在のリクエストでJWTを使用しているアカウントはログオフされます。 JWTはもう使用できません。 |
error_status | 数値 | 非対象 | 401 | ログオフ時に返されるエラーコード。 |
error_body | String | 非対象 | '{"message":"invalid token"}' | ログオフ時の応答の本体。 |
ttl | 数値 | 非対象 | - | Redisに保存されているキーの生存時間 (TTL) 。 単位は秒です。 この設定は、ログオフ後にJWTが無効化される期間を決定します。 この設定が指定されていない場合、TTLはペイロードのexpフィールドの値から現在の時刻を引いた値に等しくなります。 ペイロードにexpフィールドが含まれていない場合、デフォルトのTTLは86,400秒 (24時間) です。 |
次の表に、ログインタイプの設定フィールドを示します。
項目 | データ型 | 必須 / 任意 | デフォルト値 | 説明 |
key_prefix | String | 非対象 | higress_jwt_logout_ | Redisに格納されているキーのプレフィックス。 |
キー | 文字列の配列 | 非対象 | ["iss" 、"aud" 、"sub"] | JWTペイロード内の単一デバイスのログオン識別子。 現在の要求内のJWTペイロードが同じフィールドを含むが、要求JWTが成功したログオンのJWTと正確に同じでない場合、システムは現在の要求を繰り返されたログオン要求と見なし、要求を拒否する。 Redisで正常にログオンするためのJWTのキーが期限切れになるまで、システムはリクエストを許可します。 現在のリクエストのJWTペイロードにフィールドが含まれていない場合、エラー401無効なトークンが報告されます。 |
パス | String | 非対象 | /jwt_login | URLパスのサフィックスと一致するために使用される文字列。 URLパスのサフィックスが指定された文字列と一致する場合、アカウントは現在のリクエストでJWTを使用してシステムに強制的にログオンします。 正常なログオンに使用され、同じペイロード特性を持つJWTは、ログオフ時に無効になります。 |
error_status | 数値 | 非対象 | 403 | 繰り返されるログオンに対して返されるエラーコード。 |
error_body | String | 非対象 | '{"message":"already login on other device"}' | 繰り返しログオンの応答本文。 |
ttl | 数値 | 非対象 | - | Redisに保存されているキーのTTL。 単位は秒です。 このフィールドは、単一デバイスのログオンに使用されるJWTの有効期間を決定します。 このフィールドが指定されていない場合、TTLはペイロードのexpフィールドの値から現在の時刻を引いた値に等しくなります。 ペイロードにexpフィールドが含まれていない場合、デフォルトのTTLは86,400秒 (24時間) です。 |
設定例
ApsaraDB for Redisインスタンスの使用
Redis インスタンス用の ApsaraDB を作成します。 詳細については、「概要」をご参照ください。
ログオフとログオンの設定を有効にします。 プラグインがリクエストを処理すると、ログオフ設定チェック用の1つのRedis読み取りリクエストと、ログオン設定チェック用の2つのRedis読み取りリクエストが生成されます。 ログオフや初回ログオンなどのまれなケースでは、さらに2つのRedis書き込みリクエストが生成されます。 ApsaraDB for Redisインスタンスの容量を見積もるには、プラグインで処理されるリクエストのスループットに2を掛けます。
ApsaraDB for Redisインスタンスを設定したら、インスタンスのVPCエンドポイントを取得します。 例: r-xxxxxxx.redis.rds.aliyuncs.com。
サービスを追加します。 サービスソースドロップダウンリストからDNSドメイン名を選択し、サービスポートフィールドにRedisポート番号 (ほとんどの場合6379) を入力し、ドメイン名フィールドにVPCエンドポイントを入力し、TLSモードドロップダウンリストから無効を選択します。 詳細については、「サービスの作成」をご参照ください。
次の内容をプラグイン設定に追加して、ApsaraDB for Redisインスタンスに接続します。
redis: service: redis.dns port: 6379Redisサービスのパスワードを設定する場合は、次のコンテンツを追加します。
redis: service: redis.dns port: 6379 password: ****** # Enter the password that you specify.
JWTログオフ機能の実装
適用シナリオ
JWTはステートレストークンです。 JWTが発行された場合、有効期限が切れるまで有効です。 特定のjwtが使用されている場合、JWT-logoutプラグインを使用して強制ログオフを実装できます。
仕組み
リクエストパスのサフィックスがプラグイン構成のパスと一致する場合、ログオフメカニズムがトリガーされます。 ApsaraDB for Redisインスタンスは、ログオフのJWTを記録します。 ApsaraDB for Redisインスタンスに格納されているキーは、設定されたプレフィックスと、現在のJWTペイロードから抽出されたキーと値で構成されます。
リクエストに含まれるJWTのペイロードがApsaraDB for Redisインスタンスに格納されているキーの特性と一致する場合、システムは現在のJWTが無効であると見なし、リクエストを拒否します。
ApsaraDB for Redisインスタンスに保存されているキーのデフォルトの有効期限は、JWTペイロードの
expフィールドに基づいて計算されます。 これは、JWTが期限切れになるまでキーを格納できることを意味します。
プラグインのデフォルトの推奨ログオフキーは ["jti"] で、
jtiはJWTを一意に識別するペイロードフィールドです。 JWT標準で指定されているように、JWTペイロードのjti値がApsaraDB for Redisインスタンスに記録されている値と同じである場合、JWT全体はまったく同じです。 したがって、jtiはJWTのログオフ状態をマークするために使用できます。ApsaraDB for Redisインスタンスに格納されているキーの連結ルール:
<key_prefix><PayloadKey >#< PayloadValue>PayloadKeyは、数字記号 (#) で区切られたキーのリストです。 PayloadValueは、数字記号 (#) で区切られたキー値のリストです。 例:higress_jwt_logout_jti#iss###xxxxx#abcdeこのプラグインは、ログオフ中に現在の要求で搬送されるトークンのみを無効にすることができる。 前述のキー連結ルールに基づいて、ApsaraDB for Redisコンソールでトークンを手動で指定することもできます。 ゲートウェイがApsaraDB for Redisインスタンスにキーが存在することを検出した場合、ゲートウェイは関連するJWTに基づくアクセス要求を拒否します。
例
プラグイン設定:
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"}ログオフをトリガーします。
curl http://xxx.hello.com/test/jwt_logout -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJ4eHh4IiwiaXNzIjoiYWJjZCIsInN1YiI6InRlc3QiLCJhdWQiOiJ3d3cudGVzdC5jb20iLCJpYXQiOjE2NjU2NjA1MjcsImV4cCI6MTg2NTY3MzgxOX0.tmKF6qc1mOWNyCCzBOT2XKNoEGeEgr3EbhTKAQfq1io' # The following result is returned: {"message": "logout success"}トークンpayload:
{ "jti": "xxxx", "iss": "abcd", "sub": "test", "aud": "www.test.com", "iat": 1665660527, "exp": 1865673819 }この場合、キー
higress_jwt_logout_jti##xxxxはApsaraDB for Redisインスタンスに格納されます。ログオフ後、JWTに基づくアクセスは許可されません。
curl http://xxx.hello.com/test/abc -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJ4eHh4IiwiaXNzIjoiYWJjZCIsInN1YiI6InRlc3QiLCJhdWQiOiJ3d3cudGVzdC5jb20iLCJpYXQiOjE2NjU2NjA1MjcsImV4cCI6MTg2NTY3MzgxOX0.tmKF6qc1mOWNyCCzBOT2XKNoEGeEgr3EbhTKAQfq1io' # The following result is returned: {"message":"invalid token"}
JWTに基づく強制ログオフの実装
適用シナリオ
アカウントが複数のデバイスへのログオンに使用され、JWT認証がログオンに使用される場合、異なるJWTが異なるデバイス上で発行され得る。 この場合、jwt-logoutプラグインを使用して、アカウントが一度に1つのデバイスにのみログオンできるようにすることができます。
仕組み
リクエストが開始されると、システムは現在のリクエストからJWTを抽出し、設定されたプレフィックスと現在のJWTペイロードから抽出されたキーと値に基づいてRedisキーを構成します。 次に、システムはApsaraDB for Redisインスタンスのキーに対応する値を照会します。 値が現在のJWTのキー値と一致しない場合、システムはアクセス要求を拒否します。
値が存在しない場合、現在のJWTがRedisキーに書き込まれます。 ApsaraDB for Redisインスタンスのキーのデフォルトの有効期限は、JWTペイロードの
expフィールドに基づいて計算されます。 これは、JWTが期限切れになるまでキーを格納できることを意味します。 JWTの有効期間中、同じペイロード特性を有する他のJWTに基づくアクセス要求は許可されない。リクエストサフィックスがプラグイン構成の
パスと一致する場合、強制ログオフメカニズムがトリガーされ、現在のJWTが関連するRedisキーの値に書き込まれます。 正常なログオンに使用され、同じペイロード特性を持つJWTは、ログオフ時に無効になります。 これにより、単一デバイスのログオンが保証されます。
プラグインのデフォルトの推奨ログオンキーは ["iss","aud","sub"] です。 キーにおいて、
issはJWT発行者を示し、audはJWT使用シナリオを示し、subはJWTのサブジェクトを示す。 ほとんどの場合、この組み合わせを使用して、単一デバイスのログオンを保証できます。ApsaraDB for Redisインスタンスに格納されているキーの連結ルール:
<key_prefix><PayloadKey >#< PayloadValue>PayloadKeyは、数字記号 (#) で区切られたキーのリストです。 PayloadValueは、数字記号 (#) で区切られたキー値のリストです。 例:higress_jwt_login_iss#aud#sub##xxxxx#abcde#fffff同じペイロード特性を持つJWTの場合、リクエストに使用される最初のJWTは、ApsaraDB For Redisインスタンスに自動的に書き込まれます。 これは、プラグインの単一デバイスログオン機能を実装するのに役立ちます。 したがって、強制ログオンのためにAPI操作を呼び出す必要はありません。 ログオンシナリオで強制ログオフが必要な場合にのみ、API操作を呼び出す必要があります。
ログオフロジックをトリガーすると、ApsaraDB for Redisインスタンスに保存されている現在のJWTのログオンキーがクリアされます。 このルールは、JWTログオフ機能を有効にする場合にも適用されます。
例
プラグイン設定:
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"}正常にログオン操作を実行します。
curl http://xxx.hello.com/test/abc -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJ6enp6IiwiaXNzIjoiYWJjZCIsImF1ZCI6Ind3dy5leGFtcGxlLmNvbSIsInN1YiI6InRlc3QiLCJpYXQiOjE2NjU2NjA1MjcsImV4cCI6MTg2NTY3MzgxOX0.WljMr5ucxfLF8SmeaaL25c0QG3IX04HoD0als9gglYg'トークンpayload:
{ "jti": "zzzz", "iss": "abcd", "aud": "www.example.com", "sub": "test", "iat": 1665660527, "exp": 1865673819 }この場合、
higress_jwt_login_iss#aud#sub###abc d#www.example.com#abcdキーはApsaraDB for Redisインスタンスに格納され、値は現在のJWTと同じです。リクエスト内のJWTペイロードが同じペイロード特性を持つ場合、アクセスリクエストを拒否します。
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"}トークンpayload:
{ "jti": "yyyyy", "iss": "abcd", "aud": "www.example.com", "sub": "test", "iat": 1665660527, "exp": 1865673819 }ペイロード特性は、現在のJWTおよびステップ1のJWTについて同じである。 しかしながら、非特性体
jtiは、2つのJWT間で異なる。 したがって、JWTに基づくアクセス要求は拒否される。強制ログオンを実行します。
curl http://xxx.hello.com/test/jwt_login -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJqdGkiOiJ5eXl5eSIsImlzcyI6ImFiY2QiLCJhdWQiOiJ3d3cuZXhhbXBsZS5jb20iLCJzdWIiOiJ0ZXN0IiwiaWF0IjoxNjY1NjYwNTI5LCJleHAiOjE4NjU2NzM4MTl9.6vi6eKPWSKHQxfzBPrj3-SWI4Q5zGtWhqp38JIN3FEo' # The following result is returned: {"message":"login success"}この場合、
higress_jwt_login_iss#aud#sub###abc d#www.example.com#abcdキーはApsaraDB for Redisインスタンスに格納され、値は現在のJWTの値に置き換えられます。現在のJWTを使用して、ページに正常にアクセスします。
curl http://xxx.hello.com/test/abc -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJqdGkiOiJ5eXl5eSIsImlzcyI6ImFiY2QiLCJhdWQiOiJ3d3cuZXhhbXBsZS5jb20iLCJzdWIiOiJ0ZXN0IiwiaWF0IjoxNjY1NjYwNTI5LCJleHAiOjE4NjU2NzM4MTl9.6vi6eKPWSKHQxfzBPrj3-SWI4Q5zGtWhqp38JIN3FEo'手順1でJWTを使用すると、失敗メッセージが返されます。
curl http://xxx.hello.com/test/abc -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJqdGkiOiJ4eHh4IiwiaXNzIjoiYWJjZCIsImF1ZCI6Ind3dy5leGFtcGxlLmNvbSIsInN1YiI6InRlc3QiLCJpYXQiOjE2NjU2NjA1MjcsImV4cCI6MTg2NTY3MzgxOX0.P0WtBTHJzUJvklu9q8XSRszfPbgojrZHg7t4ZaYfKGo' # The following result is returned: {"message":"already login on other device"}
エラーコード
HTTPステータスコード | エラーメッセージ | 理由 |
401 | 無効なトークン | リクエストヘッダーにJWTが指定されていないか、JWT形式が無効であるか、JWTが期限切れです。 |
500 | redisサーバーエラー | ApsaraDB for Redisインスタンスへのアクセスがタイムアウトするか、失敗します。 |