すべてのプロダクト
Search
ドキュメントセンター

API Gateway:jwt-ログアウト

最終更新日:Jan 09, 2025

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サービスの名前。 例:

  • 固定アドレス: my-redis.static

  • DNSドメイン名: my-redis.dns

  • ACK: my-redis.default.svc.cluster.local

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インスタンスの使用

  1. Redis インスタンス用の ApsaraDB を作成します。 詳細については、「概要」をご参照ください。

  2. ログオフとログオンの設定を有効にします。 プラグインがリクエストを処理すると、ログオフ設定チェック用の1つのRedis読み取りリクエストと、ログオン設定チェック用の2つのRedis読み取りリクエストが生成されます。 ログオフや初回ログオンなどのまれなケースでは、さらに2つのRedis書き込みリクエストが生成されます。 ApsaraDB for Redisインスタンスの容量を見積もるには、プラグインで処理されるリクエストのスループットに2を掛けます。

  3. ApsaraDB for Redisインスタンスを設定したら、インスタンスのVPCエンドポイントを取得します。 例: r-xxxxxxx.redis.rds.aliyuncs.com。

  4. サービスを追加します。 サービスソースドロップダウンリストからDNSドメイン名を選択し、サービスポートフィールドにRedisポート番号 (ほとんどの場合6379) を入力し、ドメイン名フィールドにVPCエンドポイントを入力し、TLSモードドロップダウンリストから無効を選択します。 詳細については、「サービスの作成」をご参照ください。

  5. 次の内容をプラグイン設定に追加して、ApsaraDB for Redisインスタンスに接続します。

    redis:
      service: redis.dns
      port: 6379

    Redisサービスのパスワードを設定する場合は、次のコンテンツを追加します。

    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"}
  1. ログオフをトリガーします。

    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インスタンスに格納されます。

  2. ログオフ後、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"}
  1. 正常にログオン操作を実行します。

    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と同じです。

  2. リクエスト内の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に基づくアクセス要求は拒否される。

  3. 強制ログオンを実行します。

    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インスタンスへのアクセスがタイムアウトするか、失敗します。