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

API Gateway:JWTベースの認証

最終更新日:Jul 31, 2024

Alibaba Cloud API Gatewayは、JSON Webトークン (JWT) に基づいてAPIへのアクセスを許可するためのメカニズムを提供します。 このメカニズムを使用して、セキュリティ設定をカスタマイズできます。

1. トークンベースの認証

1.1 概要

API Gatewayは、オープンAPIを呼び出すAPI呼び出し元のIDを検証し、検証結果に基づいて要求されたリソースを呼び出し元に返すかどうかを決定します。 トークンは、ID認証に使用されるメカニズムです。 このメカニズムに基づいて、アプリケーションは、サーバ側でユーザ認証情報またはセッション情報を保持する必要がない。 これにより、ステートレスおよび分散webアプリケーション認証が実装され、アプリケーション拡張が容易になります。

1.2 手順

image

上の図は、JWT認証プラグインを使用して認証を実装するAPI Gatewayのワークフローを示しています。 説明:

  1. クライアントはAPI Gatewayにリクエストを送信します。 リクエストにはトークンが含まれています。

  2. API Gatewayは、JWT認証プラグインで設定された公開鍵を使用して、リクエスト内のトークンを検証します。 リクエストが検証に合格した場合、API Gatewayはリクエストをバックエンドサービスに渡します。

  3. バックエンドサービスは要求を処理し、応答を返します。

  4. API Gatewayは、バックエンドサービスの応答をクライアントに返します。

その過程で、API Gatewayを使用すると、独自のユーザーシステムを使用して、トークンベースのAPIアクセス認証を実装できます。 次のセクションでは、API Gatewayが認証に使用する構造化JWTについて説明します。

1.3 JWT

1.3.1 概要

JWTは、ネットワークアプリケーション環境間で宣言を送信するために使用されるJSONベースのオープンスタンダード (RFC 7519) です。 JWTは、クライアントがリソースサーバーからリソースを取得するのを支援するために、ユーザーID、ユーザーの役割、権限などの情報を含む独立した認証トークンとして機能します。 JWTは、他のビジネスシナリオに必要な追加の請求情報も提供できます。 JWTは、分散サイトでのログオンに適しています。

1.3.2 JWTの构成

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

前の例で説明したように、JWTは次の部分で構成される文字列です。

  • ヘッダー

  • ペイロード

  • Signature

ヘッダーは次の部分で構成されています。

  • トークンのタイプ (JWT)

  • 暗号化アルゴリズム

JSON形式の完全なヘッダーの例:

{
  'typ': 'JWT',
  'alg': 'HS256'
}

ヘッダはBase64で符号化され、JWTの第1の部分を形成する。 エンコードするヘッダーは対称的にデコードできます。

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

ペイロード

ペイロードは、クレームのセットによって指定される有効な情報を含む。 クレーム:

iss: token issuer. This claim is a string.
sub: Subject Identifier. The identifier of a user. The value of this claim is unique. This claim can contain a maximum of 255 ASCII characters that are case-sensitive.
aud: Audience. Recipients for which the JWT is intended. The value of this claim is a string array that is case-sensitive.
exp: Expiration Time. The timestamp at which the token expires. When the timestamp is reached, the token becomes invalid. This claim is an integer representing the number of seconds that have elapsed since the epoch time January 1, 1970, 00:00:00 UTC.
iat: the time the token was issued. This claim is an integer representing the number of seconds that have elapsed since the epoch time January 1, 1970, 00:00:00 UTC.
jti: the unique identifier of the token. The value of this claim is a cryptographic random value to prevent conflicts. This claim functions in the same way as a random entropy component that is added to the structured JWT and cannot be obtained by an attacker. This helps prevent token guessing attacks and replay attacks.

カスタムクレームを追加することもできます。 次の例では、name要求が追加されています。

{
  "sub": "1234567890",
  "name": "John Doe"
}

ペイロードはBase64で符号化され、JWTの第2の部分を形成する。

JTdCJTBBJTIwJTIwJTIyc3ViJTIyJTNBJTIwJTIyMTIzNDU2Nzg5MCUyMiUyQyUwQSUyMCUyMCUyMm5hbWUlMjIlM0ElMjAlMjJKb2huJTIwRG9lJTIyJTBBJTdE

Signature

これはJWTの3番目の部分です。 この部分は、ピリオド (.) を使用してBase64-encodedヘッダーとBase64-encodedペイロードから連結された文字列を使用します。 この部分は、ヘッダーで宣言された暗号化方法を使用して暗号化されます。 $secretはユーザーの秘密鍵を示します。

// javascript
var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);
var signature = HMACSHA256(encodedString, '$secret');

これらの3つの部分は、ピリオド (.) によって連結されて完全な文字列を形成します。

1.3.3 承認スコープと有効期間

API Gatewayでは、発行されたトークンを使用して、特定のAPIグループ内のJWT認証プラグインにバインドされているすべてのAPIにアクセスできます。 詳細な権限管理が必要な場合、バックエンドサービスは認証のためにトークンを検証する必要があります。 トークンの有効性については、API Gatewayは各APIリクエストのトークンのexpクレームをチェックします。 トークンの有効期限が切れた場合、API Gatewayはトークンを無効と見なし、APIリクエストを拒否します。 トークンの有効期間を指定する必要があります。 有効期間は7日未満でなければなりません。

1.3.4 JWTの特徴

  1. デフォルトでは、JWTは暗号化されません。 秘密データをJWTに書き込まないでください。

  2. JWTは、アイデンティティの認証または情報の交換に使用できます。 JWTは、特定のデータベースに対してサーバーによって実行されるクエリの数を減らすのに役立ちます。 JWTの最も顕著な欠点は、サーバーがセッションステータスを保存できないことです。 したがって、JWTの使用中は、JWTを取り消したり、JWTの権限を変更したりすることはできません。 JWTが発行された後、有効期限が切れるまで有効です。 JWTを無効にするには、サーバーに新しいロジックを展開する必要があります。

  3. JWTは、認証情報を含む。 認証情報が開示されている場合、ユーザーはJWTのすべての権限を取得できます。 JWTが盗まれる可能性を減らすために、JWTに短い有効期間を設定します。 重要な権限を使用するユーザーを認証します。

  4. JWTが盗まれる可能性を減らすには、HTTPの代わりにHTTPSを使用してデータを送信します。

2. JWT認証プラグインを使用してAPIを保護する

2.1 JWKペアの生成

方法1: オンライン生成

https://mkjwk.org をご覧ください。 JWTの生成と検証に使用する秘密鍵と公開鍵を指定します。 秘密鍵は、JWTを発行するために認証サーバによって使用される。 公開鍵は、API GatewayのJWT認証プラグインで設定され、リクエストの署名を検証します。 API Gatewayは、キーペアの2048ビットRSA SHA256暗号化アルゴリズムをサポートしています。

方法2: ローカル生成

このトピックでは、Javaの例を示します。 同様のツールが他のプログラミング言語に提供され、キーペアを生成する。 Mavenプロジェクトを作成し、次の依存関係をプロジェクトに追加します。

<dependency>
     <groupId>org.bitbucket.b_c</groupId>
    <artifactId>jose4j</artifactId>
    <version>0.7.0</version>
</dependency>

次のコードを使用して、RSAキーペアを生成します。

RsaJsonWebKey rsaJsonWebKey = RsaJwkGenerator.generateJwk(2048);
rsaJsonWebKey.setKeyId("authServer");
final String publicKeyString = rsaJsonWebKey.toJson(JsonWebKey.OutputControlLevel.PUBLIC_ONLY);
final String privateKeyString = rsaJsonWebKey.toJson(JsonWebKey.OutputControlLevel.INCLUDE_PRIVATE);

2.2 JWKペアの秘密鍵を使用してトークンを発行する

メソッド1を使用して生成されたKeypair JSON文字列、またはメソッド2を使用して生成されたprivateKeyString JSON文字列を秘密鍵として使用して、トークンを発行します。 トークンは、信頼できるユーザーに保護されたAPIへのアクセスを許可します。 詳細については、「認証サーバーがトークンを発行するためのサンプルコード」セクションの例を参照してください。 トークンを発行する形式は、特定のビジネス要件に基づいて決定されます。 トークン発行機能を本番環境にデプロイし、共通APIを設定できます。 次に、訪問者はユーザー名とパスワードを使用してトークンを取得できます。 または、ローカルでトークンを生成し、特定のユーザーのトークンをコピーできます。

2.3 JWT認証プラグインのJWKペアの公開キーを設定する

  1. API Gatewayコンソールにログインします。

  2. 左側のナビゲーションウィンドウで、[APIの管理]> [プラグイン] を選択します。

  3. [プラグイン] ページで、右上隅の [プラグインの作成] をクリックします。

  4. [プラグインの作成] ページで、プラグインの種類を [JWT権限付与] に設定します。 次の例は、JWT認証プラグインの設定を示しています。 詳細については、「」をご参照ください。

---
parameter: X-Token         # The parameter from which the JWT is read. This parameter corresponds to a parameter in an API request.
parameterLocation: header  # The location from which the JWT is read. Valid values: query and header. This parameter is optional if Request Mode for the bound API is set to Map (Filter Out Unknown Parameters) or Map (Pass-through Unknown Parameters). This parameter is required if Request Mode for the bound API is set to Pass-through.
claimParameters:           # The claims to be converted into parameters. API Gateway maps JWT claims to backend parameters.
- claimName: aud           # The name of the JWT claim, which can be public or private.
  parameterName: X-Aud     # The name of the backend parameter, to which the JWT claim is mapped.
  location: header         # The location of the backend parameter, to which the JWT claim is mapped. Valid values: query, header, path, and formData.
- claimName: userId        # The name of the JWT claim, which can be public or private.
  parameterName: userId    # The name of the backend parameter, to which the JWT claim is mapped.
  location: query          # The location of the backend parameter, to which the JWT claim is mapped. Valid values: query, header, path, and formData.
preventJtiReplay: false    # Controls whether to enable the anti-replay check for jti. Default value: false.
#
# `Public Key` in the `JSON Web Key` pair, which is generated in the "Generate a JWK pair" section
jwk:
  kty: RSA
  e: AQAB
  use: sig
  alg: RS256
  n: qSVxcknOm0uCq5vGsOmaorPDzHUubBmZZ4UXj-9do7w9X1uKFXAnqfto4TepSNuYU2bA_-tzSLAGBsR-BqvT6w9SjxakeiyQpVmexxnDw5WZwpWenUAcYrfSPEoNU-0hAQwFYgqZwJQMN8ptxkd0170PFauwACOx4Hfr-9FPGy8NCoIO4MfLXzJ3mJ7xqgIZp3NIOGXz-GIAbCf13ii7kSStpYqN3L_zzpvXUAos1FJ9IPXRV84tIZpFVh2lmRh0h8ImK-vI42dwlD_hOIzayL1Xno2R0T-d5AwTSdnep7g-Fwu8-sj4cCRWq3bd61Zs2QOJ8iustH0vSRMYdP5oYQ

2.4 JWT認証プラグインをAPIにバインドする

[プラグインリスト] ページで、作成したJWT認証プラグインを見つけ、[操作] 列の [APIのバインド] をクリックします。 [APIのバインド] ダイアログボックスで、APIを選択するAPIグループと環境を指定し、選択したAPIペインにAPIを追加して、[OK] をクリックします。

API GatewayコンソールのAPIデバッグ機能は、JWT認証プラグインをサポートしていません。 JWT認証プラグインにバインドされているAPIをテストするには、Postmanを使用するか、コマンドラインインターフェイス (CLI) でcurlコマンドを実行することを推奨します。

3. エラーコード

Status

Code

Message

説明

400

I400JR

JWTが必要

JWT関連のパラメーターは見つかりません。

403

S403JI

preventJtiReplay:trueのときにjtiを要求する必要があります

JWT認証プラグインでpreventJtiReplayがtrueに設定されている場合、有効なjtiクレームはリクエストに含まれません。

403

S403JU

JWTのクレームjtiが使用されている

リクエストに含まれるjtiクレームは、JWT認証プラグインでpreventJtiReplayがtrueに設定されている場合に使用されています。

403

A403JT

無効なJWT: ${理由}

リクエストに含まれるJWTが無効です。

400

I400JD

JWTのシリアル化に失敗しました: ${トークン}

リクエストから読み取られたJWTの解析に失敗しました。

403

A403JK

JWK, kid :${ kid} が見つかりません

リクエストに含まれるJWTで設定されているkidに一致するJWKはありません。

403

A403JE

JWTの有効期限は ${Date} です

リクエストから読み取られたJWTは期限切れです。

400

I400JP

無効なJWTプラグイン設定: ${JWT}

JWT認証プラグインが正しく設定されていません。

HTTP応答メッセージに、A403JTやI400JDなどのX-Ca-Error-codeヘッダーにErrorCodeで指定された予期しない応答コードが含まれている場合は、jwt.io Webサイトにアクセスしてトークンの有効性と形式を確認できます。

4. トークンを発行する認証サーバーのサンプルコード

import java.security.PrivateKey; 
import org.jose4j.json.JsonUtil;
import org.jose4j.jwk.RsaJsonWebKey;
import org.jose4j.jwk.RsaJwkGenerator;
import org.jose4j.jws.AlgorithmIdentifiers;
import org.jose4j.jws.JsonWebSignature;
import org.jose4j.jwt.JwtClaims;
import org.jose4j.jwt.NumericDate;
import org.jose4j.lang.JoseException;
public class GenerateJwtDemo {
    public static void main(String[] args) throws JoseException  {
          // Use the value of the keyId parameter that you specified when you configured basic information for the authorization API operation.
        String keyId = "uniq_key";
          // Use the key pair generated in the "Generate a JWK pair" section.
        String privateKeyJson = "{\n"
            + "  \"kty\": \"RSA\",\n"
            + "  \"d\": "
            +
            "\"O9MJSOgcjjiVMNJ4jmBAh0mRHF_TlaVva70Imghtlgwxl8BLfcf1S8ueN1PD7xV6Cnq8YenSKsfiNOhC6yZ_fjW1syn5raWfj68eR7cjHWjLOvKjwVY33GBPNOvspNhVAFzeqfWneRTBbga53Agb6jjN0SUcZdJgnelzz5JNdOGaLzhacjH6YPJKpbuzCQYPkWtoZHDqWTzCSb4mJ3n0NRTsWy7Pm8LwG_Fd3pACl7JIY38IanPQDLoighFfo-Lriv5z3IdlhwbPnx0tk9sBwQBTRdZ8JkqqYkxUiB06phwr7mAnKEpQJ6HvhZBQ1cCnYZ_nIlrX9-I7qomrlE1UoQ\",\n"
            + "  \"e\": \"AQAB\",\n"
            + "  \"kid\": \"myJwtKey\",\n"
            + "  \"alg\": \"RS256\",\n"
            + "  \"n\": \"vCuB8MgwPZfziMSytEbBoOEwxsG7XI3MaVMoocziP4SjzU4IuWuE_DodbOHQwb_thUru57_Efe"
            +
            "--sfATHEa0Odv5ny3QbByqsvjyeHk6ZE4mSAV9BsHYa6GWAgEZtnDceeeDc0y76utXK2XHhC1Pysi2KG8KAzqDa099Yh7s31AyoueoMnrYTmWfEyDsQL_OAIiwgXakkS5U8QyXmWicCwXntDzkIMh8MjfPskesyli0XQD1AmCXVV3h2Opm1Amx0ggSOOiINUR5YRD6mKo49_cN-nrJWjtwSouqDdxHYP-4c7epuTcdS6kQHiQERBd1ejdpAxV4c0t0FHF7MOy9kw\"\n"
            + "}";
        JwtClaims claims = new JwtClaims();
        claims.setGeneratedJwtId();
        claims.setIssuedAtToNow();
        // The validity period is required and must be less than seven days.
        NumericDate date = NumericDate.now();
        date.addSeconds(120*60);
        claims.setExpirationTime(date);
        claims.setNotBeforeMinutesInThePast(1);
        claims.setSubject("YOUR_SUBJECT");
        claims.setAudience("YOUR_AUDIENCE");
        // Add custom parameters. All parameter values must be of the STRING type.
        claims.setClaim("userId", "1213234");
        claims.setClaim("email", "userEm***@youapp.com");
        JsonWebSignature jws = new JsonWebSignature();
        jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
          // The KeyIdHeaderValue parameter is required.
        jws.setKeyIdHeaderValue(keyId);
        jws.setPayload(claims.toJson());
        PrivateKey privateKey = new RsaJsonWebKey(JsonUtil.parseJson(privateKeyJson)).getPrivateKey();
        jws.setKey(privateKey);
        String jwtResult = jws.getCompactSerialization();
        System.out.println("Generate Json Web token , result is " + jwtResult);
    }
}

以下の点にご注意ください。

  1. keyIdパラメーターの値は、API Gatewayで一意である必要があります。 keyIdパラメーターで次の値を一貫して保持する必要があります。

  • 「JWKペアの生成」セクションで指定したkeyIdパラメーターの値。

  • 認可API操作の基本情報を設定するときに指定したkeyIdパラメーターの値。

  • コードで指定されているkeyIdパラメーターの値。JsonWebSignatureオブジェクトのKeyIdHeaderValueパラメーターの値です。 KeyIdHeaderValueパラメーターが必要です。

  1. メソッド1またはを使用して生成されたKeypair JSON文字列にprivateKeyJsonを設定する必要があります。

    「JWKペアの生成」セクションのメソッド2を使用して生成されるprivateKeyString JSON文字列。

  2. 有効期間は必須であり、7日未満でなければなりません。

  3. カスタムパラメーターを追加する場合、すべてのパラメーター値はSTRING型である必要があります。