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

API Gateway:コンシューマー認証と承認

最終更新日:Nov 09, 2025

クラウドネイティブ API Gateway は、グローバル認証、ルートレベルの認証、およびコンシューマーの権限付与をサポートし、権限のあるリクエストのみがサービスにアクセスできるようにします。このトピックでは、クラウドネイティブ API Gateway で認証と権限付与を使用して、コンシューマーがリソースに安全にアクセスできるようにする方法について説明します。

背景情報

グローバル認証と権限付与は、統合ログインなどの B2C (business-to-consumer) シナリオに最適です。対照的に、ルートレベルおよび API レベルのコンシューマー認証は、パートナーに API アクセスを許可するなどの B2B (business-to-business) シナリオ向けに設計されています。

比較

グローバル認証と承認

ルート認証 + コンシューマー権限付与

シナリオ

統合ログインや認証など、顧客向け (ToC) のシナリオ。

パートナーへの API アクセス権の付与など、B2B シナリオ。

主な違い

認証を有効にすると、権限付与も有効になります。

認証を有効にした後、権限付与を個別に設定する必要があります。

設定エントリポイント

[インスタンス] > [セキュリティ管理] > [グローバル認証と権限付与]

  1. [API 管理] > [HTTP API 詳細] > [ルート管理] > [ポリシー構成] > [コンシューマー認証]

  2. [API 管理] > [WebSocket API 詳細] > [ルート管理] > [ポリシー構成] > [コンシューマー認証]

  3. [API 管理] > [REST API 詳細] > [ポリシーのアタッチ] > [コンシューマー認証]

  4. [コンシューマー] > [コンシューマー詳細] > [コンシューマー承認]

認証メソッドの設定 (JWT 認証を例として)

  1. 設定を作成するときに、グローバルの [JWKS] 設定を入力します。

  2. issue および sub フィールドの値を入力します。これらのフィールドは、JSON Web トークン (JWT) を検証するために使用されます。

  1. コンシューマー設定を作成するときに、コンシューマーの JWKS 設定を入力します。

  2. コンシューマー ID を入力し、JWT に関連付けられているコンシューマーを検証します。デフォルトでは、ゲートウェイは payloaduid フィールドをコンシューマー ID として使用しますが、このフィールドはカスタマイズできます。

権限付与メソッドの設定

設定を作成するときに、ブラックリストまたはホワイトリストの [ドメイン名][パス] のリストを入力します。

  • [ブラックリストモード]: リストにある [ドメイン名][パス] へのリクエストには認証が必要です。他のすべてのリクエストは、認証なしでアクセスできます。

  • [ホワイトリストモード]: リストにあるドメイン名と [パス] へのリクエストには認証は必要ありません。他のすべてのリクエストには認証が必要です。

  1. ルートまたは API の [ポリシー設定] で、[認証] を有効にします。

  2. [コンシューマー権限付与] で、認証が有効になっているルートまたは API に権限を付与します。

注意事項

コンシューマー認証を有効にすると、ポリシーはすぐに有効になります。ルートまたは API がすでに公開されているが、コンシューマーまたは権限付与ルールが設定されていない場合、すべてのアクセスリクエストはデフォルトで拒否されます。

コンシューマーの認証と権限付与の使用

JWT 認証

JWT 認証フローの概要

  1. クライアントは API Gateway に認証リクエストを送信します。リクエストには通常、エンドユーザーのユーザー名とパスワードが含まれます。

  2. ゲートウェイはリクエストをバックエンドサービスに直接転送します。

  3. バックエンドサービスは、リクエストからユーザー名やパスワードなどの検証情報を読み取って検証します。情報が検証されると、サービスは秘密鍵を使用して標準トークンを生成し、ゲートウェイに返します。

  4. ゲートウェイはトークンを含む応答をクライアントに返します。クライアントはこのトークンをローカルにキャッシュする必要があります。

  5. クライアントはトークンを使用してビジネスリクエストを API Gateway に送信します。

  6. ゲートウェイは、ユーザーが設定した公開鍵を使用してリクエスト内のトークンを検証します。検証に合格すると、リクエストはバックエンドサービスに転送されます。

  7. バックエンドサービスはビジネスロジックを処理し、応答を送信します。

  8. ゲートウェイはビジネス応答をクライアントに返します。

以下のセクションでは、トークンを生成する方法、クライアントがゲートウェイにリクエストを送信する方法、およびゲートウェイが設定された公開鍵を使用してトークンを検証する方法について説明します。

認証サービスでトークンを生成する

次の Java の例は、トークンを生成する方法を示しています。他の言語の場合は、対応するツールを使用してキーペアを生成してください。

  1. Maven プロジェクトを作成し、次の依存関係を追加します:

    まず、Maven プロジェクトを作成し、次の依存関係を追加します:

    <dependency>
        <groupId>org.bitbucket.b_c</groupId>
        <artifactId>jose4j</artifactId>
        <version>0.7.0</version>
    </dependency>
  2. トークンを生成する方法を選択します。

    対称鍵または非対称鍵のいずれかを使用してトークンを生成できます。要件に合ったメソッドを選択してください。

    対称鍵を使用してトークンを生成する

    コード例:

    package org.example;
    
    import java.io.UnsupportedEncodingException;
    import java.security.PrivateKey;
    
    import org.jose4j.base64url.Base64;
    import org.jose4j.json.JsonUtil;
    import org.jose4j.jwk.OctJwkGenerator;
    import org.jose4j.jwk.OctetSequenceJsonWebKey;
    import org.jose4j.jws.AlgorithmIdentifiers;
    import org.jose4j.jws.JsonWebSignature;
    import org.jose4j.jwt.JwtClaims;
    import org.jose4j.jwt.NumericDate;
    import org.jose4j.keys.HmacKey;
    import org.jose4j.lang.JoseException;
    import sun.lwawt.macosx.CSystemTray;
    
    public class Main {
        public static void main(String[] args) throws JoseException, UnsupportedEncodingException {
            // このトピックの例を使用
            String privateKeyJson = "{\n"
                    + "    \"k\": \"VoBG-oyqVoyCr9G56ozmq8n_rlDDyYMQOd_DO4GOkEY\",\n"
                    + "    \"kty\": \"oct\",\n"
                    + "    \"alg\": \"HS256\",\n"
                    + "}";
            JwtClaims claims = new JwtClaims();
            claims.setGeneratedJwtId();
            claims.setIssuedAtToNow();
            // 有効期限を 7 日未満に設定
            NumericDate date = NumericDate.now();
            date.addSeconds(120*60);
            claims.setExpirationTime(date);
            claims.setNotBeforeMinutesInThePast(1);
            // カスタムパラメーターを追加します。すべての値は String 型である必要があります。
            // コンシューマー ID を設定
            claims.setClaim("uid", "11215ac069234abcb8944232b79ae711");
            JsonWebSignature jws = new JsonWebSignature();
            // 暗号化アルゴリズムを設定
            jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.HMAC_SHA256);
            jws.setKey(new HmacKey(Base64.decode(JsonUtil.parseJson(privateKeyJson).get("k").toString())));
            jws.setPayload(claims.toJson());
            String jwtResult = jws.getCompactSerialization();
            System.out.println("Generated JSON Web Token result is: \n" + jwtResult);
        }
    }

    コード設定:

    • privateKeyJson: これは、コンシューマーを作成するときに使用される JSON Web Key Set (JWKS) です。コンシューマーを作成するときに JWKS を記録するか、後でコンシューマーの基本設定ページから取得できます。

    • コンシューマー ID を設定します。たとえば、claims.setClaim("uid", "11215ac069234abcb8944232b79ae711") です。コンソールは、コンシューマーを作成するときにデフォルトのコンシューマー ID を生成します。この ID は必要に応じて変更できます。コンシューマー ID は、コンシューマーの基本設定ページから取得することもできます。

    • 暗号化アルゴリズムを設定します。たとえば、jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.HMAC_SHA256) です。このアルゴリズムは、JWKS のアルゴリズムと一致する必要があります。

      説明

      サポートされている暗号化アルゴリズは、ES256、ES384、ES512、RS256、RS384、RS512、PS256、PS384、PS512、HS256、HS384、HS512、および EdDSA です。

      対称暗号化を使用する場合は、「k」の値をデコードします。

      jws.setKey(new HmacKey(Base64.decode(JsonUtil.parseJson(privateKeyJson).get("k").toString())));
    • 有効期限を設定します。有効期限は 7 日未満である必要があります。トークンの有効期限が切れたら、セキュリティを確保するために再生成する必要があります。

      ...
          NumericDate date = NumericDate.now();
          date.addSeconds(120*60);
          claims.setExpirationTime(date);
          claims.setNotBeforeMinutesInThePast(1);
      ...
    • ビジネスニーズに合わせて、JWKS PAYLOAD にカスタムパラメーターを追加できます。

    非対称鍵を使用してトークンを生成する

    コード例:

    package org.example;
    
    import java.security.PrivateKey;
    import org.jose4j.json.JsonUtil;
    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;
    import org.jose4j.jwk.RsaJsonWebKey;
    
    public class Main {
        public static void main(String[] args) throws JoseException {
            // JWK 形式のキーの例
            String privateKeyJson = "{"
                    + "\"kty\":\"RSA\","
                    + "\"n\":\"u-8lR9lyRhu8tl4vRxOl7yfshssx5jRstabc9n4Rxrz102Z7TPFYrXBZHgf67Y0d-zx9tWd5j91WZxLHv4K6VWPN7zEWEQNn3vUg76dPHPzVkZJWziFPS1EvS4a2gRZdrE4nPogaQ72WySVC0yUF2fL0NKeOclD__coCFxn4QQjcDXyu_CUbI_FuDcdw267mVjjylAaFvOZHH0pXsV8m5zXlpc2aiemWYQJD9MtWRcoKlexWMkTwbEqW5-NWAl0Uo202ahDA1NiaQ98Ch4nw6g2E1GvwxxHkbvMuZcs5z8F5Ct_w0IPtvY7ngSyEN-WCU40oj-C5NUCy_73FpXXdWQ\","
                    + "\"e\":\"AQAB\","
                    + "\"d\":\"Uxg1IqSZazg-Y2AXhVTBrJG5egwD3yZU3qiN0IsDbx0DkFoisG2R6PXg4W9j2n7nv7sKVhgPXrXdyys5mIrDuperaVQJzrHzzlgSHQSb7VQ5Vekfanq95a5avAkvTrpF5raTkYl6G3OLZRqNhnA7Oxe6NEHVsOPxnBQignZgFtiBtCSZY4RVH6Dx4jFfBBNMC9ifyLWLpHut7eczvxI412nBkxgtEjSeFe083NlumO_ZYHbijPcQf5zFWPLEj2EvlgbSwhjc-uSAF4OljAyG_DHZYvztEIGMdxMgBHgwtEvCfzS6PeUgvUR-SB7m_L8z4gjz6TlpSYe3CnZqE69KdQ\","
                    + "\"p\":\"9mNw8U_GxbcSknueUeFFSU9wKD9E9P2ZO5RP5d7o3qGUXOfbrH_g5GMH3YJiPBDZs_2BYFrAACOY4YM-QTiXWVs4xS3OeD8AdH3wEXR_3DMEkOez3cNq3Jy3ZJabm7IUnPMIWv5gpIHghcx0YTtM5RabSgexLMKh2-6sB466378\","
                    + "\"q\":\"w0PzXI_8Q5jv15OUq-dV_Z0kp91Icumf6PEERZN4v3i3VolLBnamMiIQiF74ywclKpZmtfOQTfyL41Xj2vbm2Aus6akRsU3NhQlVtIQTzHWUuEQgMIJYDK7--FzEcZORm1qBiEffiWv6U-slyCcLcNDNT-wjMX8BrS4oWHIoCOc\","
                    + "\"dp\":\"fRRiY76yE_EqVn63Eq4ftGXFdEkaQpzzS1GxderBoTO506hI1rtcedTkS0lDgWa0fjE1mqq3SdrIY8NyuT13Z_9tRHxKkrS5EGpWkyXnOuwTZ1SY9P2dpD1SxJfIizPOTxb5qOf2O81LI-F1O18VXD8rultJUIXGEZaKcpO8vpU\","
                    + "\"dq\":\"V6EP_vMzD5b707AMYVURFx7Fi3vX_pHvzJcVBrBW2P6wsGouvDjU_tygtMKCPoL3X_RdJbynfwgeMyihd-ujz0L2F2pjYUF8QP7ecoNvays9UbBpDbwBDbge_pCLLDlAeAqW5PT0UXSew7hcnUVAciGSchKT_Kt1siVrv72DT_M\","
                    + "\"qi\":\"w5fENzxOivbbbUbawAWSuLgWPtvbTKn2XuPzwr_JzZH08-nadWwQFChcvAiCs8V-306TQOh8NfY308QpGDIq-iRfrS7CEePOjRzpHJfsaQ1IFQqzgDZ9VGdJRDlZqRHx0DbqwMlleVKTC6ER6varalbr4lKU-ZPUQLCzj0e4PMs\""
                    + "}";
    
            JwtClaims claims = new JwtClaims();
            claims.setGeneratedJwtId(); // jti (JWT ID) を自動的に生成
            claims.setIssuedAtToNow();  // 発行時刻 (iat) を現在の時刻に設定
    
            // 有効期限を 7 日未満に設定
            NumericDate date = NumericDate.now();
            date.addSeconds(120 * 60); // 有効期限を現在の時刻 + 120 分に設定
            claims.setExpirationTime(date);
            claims.setNotBeforeMinutesInThePast(1); // 有効期間の開始時刻 (nbf) を 1 分前に設定
    
            // カスタムパラメーターを追加します。すべての値は String 型である必要があります。
            // コンシューマー ID を設定
            claims.setClaim("uid", "11215ac069234abcb8944232b79ae711");
    
            JsonWebSignature jws = new JsonWebSignature();
            // 暗号化アルゴリズムを RSA-SHA256 に設定
            jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
    
            // 秘密鍵を解析して署名者に設定
            PrivateKey privateKey = new RsaJsonWebKey(JsonUtil.parseJson(privateKeyJson)).getPrivateKey();
            jws.setKey(privateKey);
    
            // ペイロードコンテンツを設定
            jws.setPayload(claims.toJson());
    
            // JWT を生成
            String jwtResult = jws.getCompactSerialization();
            System.out.println("Generated JSON Web Token result is: \n" + jwtResult);
        }
    }
    

    コード設定:

    • privateKeyJson、コンシューマー ID、および有効期限を設定します。これは、対称暗号化アルゴリズムの場合と同じです。

      暗号化アルゴリズムを設定します。たとえば、jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256) です。このアルゴリズムは、JWKS のアルゴリズムと一致する必要があります。

      非対称鍵暗号化アルゴリズムを使用してデータを暗号化するには、秘密鍵を使用する必要があります。

      ...
          jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
          PrivateKey privateKey = new RsaJsonWebKey(JsonUtil.parseJson(privateKeyJson)).getPrivateKey();
          jws.setKey(privateKey);
      ...
    • 必要に応じて、JWT の PAYLOAD にカスタムパラメーターを追加できます。

クライアントからゲートウェイへのビジネスリクエストの送信

クラウドネイティブ API Gateway は、ヘッダーでのトークンの受け渡しをサポートしています。リクエストヘッダー名とトークンのプレフィックスはカスタマイズできます。リクエストの検証中、キーとプレフィックスはコンシューマー認証設定と一致する必要があります。

  • リクエストに JWT が含まれていない場合、401 エラーが返されます。

    curl  http://xxx.hello.com/test
  • リクエストに無効な JWT が含まれている場合、401 エラーが返されます。

    curl  http://xxx.hello.com/test -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJpc3MiOiJhYmNkIiwic3ViIjoidGVzdCIsImlhdCI6MTY2NTY2MDUyNywiZXhwIjoxODY1NjczODE5fQ.-vBSV0bKeDwQcuS6eeSZN9dLTUnSnZVk8eVCXdooCQ1'
  • リクエストに有効な JWT が含まれているが、コンシューマーに API またはルートへのアクセス権がない場合、403 エラーが返されます。

    # consumer1 は次のパスのルートまたは API に対して権限がありません
    
    curl  'http://xxx.example.com/test' -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJpc3MiOiJhYmNkIiwic3ViIjoidGVzdCIsImlhdCI6MTY2NTY2MDUyNywiZXhwIjoxODY1NjczODE5fQ.-vBSV0bKeDwQcuS6eeSZN9dLTUnSnZVk8eVCXdooCQ4'

サーバーでのトークンの検証

サーバー側のトークン検証には、次の 3 つのステップが含まれます:

  1. サーバーはユーザーリクエストを受信すると、まずトークンが含まれているかどうかを確認します。含まれていない場合、リクエストは 401 エラーで拒否されます。

  2. トークンを含むリクエストの場合、サーバーは設定された JWKS の公開鍵を使用して、トークンが有効で有効期限が切れていないことを確認します。トークンが無効または期限切れの場合、リクエストは 401 エラーで拒否されます。

  3. トークンが有効な場合、サーバーは次に、トークンによって表されるコンシューマーが、リクエストされた API またはルートへのアクセスを許可されているかどうかを確認します。

一般的なエラーコード

HTTP ステータスコード

エラーメッセージ

原因

401

Jwt missing

リクエストヘッダーに JWT が含まれていません。

401

Jwt expired

JWT の有効期限が切れています。

401

Jwt verification fails

JWT ペイロードの検証に失敗しました。たとえば、`iss` クレームが一致しません。

403

Access Denied

現在のルートにアクセスする権限がありません。

AK/SK (HMAC) 認証

クライアントでの署名の生成

クライアント側の署名生成フロー:

  1. 署名対象文字列の抽出: 元のリクエストからキーデータを抽出して、署名用の文字列を作成します。

  2. 署名の生成: 暗号化アルゴリズムと設定されたシークレットキー (SK) を使用して署名対象文字列を暗号化し、署名を生成します。

  3. 署名の追加: 署名関連のすべてのヘッダーを元の HTTP リクエストに追加して、最終的な HTTP リクエストを作成します。

ステップ 1: 署名対象文字列の抽出

クライアントは HTTP リクエストからキーデータを抽出し、それを組み合わせて署名対象文字列を作成する必要があります。生成される署名対象文字列のフォーマットは次のとおりです:

HTTPMethod
Accept
Content-MD5
Content-Type
Date
Headers
PathAndParameters

これら 7 つのフィールドが署名対象文字列全体を構成します。フィールドは改行 (`\n`) で区切られます。`Headers` フィールドが空の場合、`Headers` フィールドの後に改行を追加しないでください。他のすべての空のフィールドについては、改行を保持する必要があります。署名では大文字と小文字が区別されます。各フィールドを抽出するためのルールは次のとおりです:

  • HTTPMethod: 大文字の HTTP メソッド。たとえば、POST です。

  • Accept: リクエストの `Accept` ヘッダーの値。このフィールドは空にすることができます。`Accept` ヘッダーを明示的に設定する必要があります。このヘッダーが空の場合、一部の HTTP クライアントはデフォルト値の */* を設定するため、署名検証が失敗します。

  • Content-MD5: リクエストの `Content-MD5` ヘッダーの値。このフィールドは空にすることができます。`Content-MD5` ヘッダーは、リクエストにフォーム形式ではないボディがある場合にのみ計算する必要があります。次の Java コードは、Content-MD5 値を計算する方法を示しています:

    String content-MD5 = Base64.encodeBase64(MD5(bodyStream.getbytes("UTF-8")));
  • Content-Type: リクエストの `Content-Type` ヘッダーの値。このフィールドは空にすることができます。

  • Date: リクエストの `Date` ヘッダーの値。date_offset 設定が有効になっていない場合、このフィールドは空にすることができます。それ以外の場合、ゲートウェイはこのフィールドを時間オフセット検証に使用します。

  • Headers: 署名に含める特定のヘッダーを選択できます。ヘッダー文字列を連結するためのルールは次のとおりです:

    • 署名計算に含まれるヘッダーのキーはアルファベット順にソートされ、次のように連結されます。

      HeaderKey1 + ":" + HeaderValue1 + "\n"\+
      HeaderKey2 + ":" + HeaderValue2 + "\n"\+
      ...
      HeaderKeyN + ":" + HeaderValueN + "\n"
    • ヘッダーの値が空の場合は、署名に `HeaderKey+":"+"\n"` を使用します。キーとコロンは保持する必要があります。

    • 署名に含まれるすべてのヘッダーキーのカンマ区切りリストは、`X-Ca-Signature-Headers` ヘッダーに配置されます。

    • 次のヘッダーはヘッダー署名計算に含まれません: `X-Ca-Signature`、`X-Ca-Signature-Headers`、`Accept`、`Content-MD5`、`Content-Type`、および `Date`。

  • PathAndParameters: このフィールドには、パスと、クエリおよびフォームのすべてのパラメーターが含まれます。次のように構成されます:

    Path + "?" + Key1 + "=" + Value1 + "&" + Key2 + "=" + Value2 + ... "&" + KeyN + "=" + ValueN
    重要
    • クエリとフォームのパラメーターペアのキーはアルファベット順にソートされ、上記のように連結されます。

    • クエリまたはフォームパラメーターがない場合は、パスのみを使用します。? は追加しないでください。

    • パラメーターの値が空の場合は、キーのみを署名に含めます。等号は追加しないでください。

    • クエリまたはフォームに配列パラメーター (同じキー、異なる値) が存在する場合、署名計算には最初の値を使用します。

ステップ 2: 署名の暗号化

クライアントが HTTP リクエストからキーデータを抽出し、署名対象文字列をアセンブルした後、文字列を暗号化し、結果をエンコードして最終的な署名を生成する必要があります。暗号化フォーマットは次のとおりです。ここで、stringToSign は抽出された署名対象文字列、secret はアクセスキー (AK)/SK 認証設定のシークレットキー (SK)、sign は最終的に生成された署名です:

Mac hmacSha256 = Mac.getInstance("HmacSHA256"); // Macインスタンスを取得
byte[] secretBytes = secret.getBytes("UTF-8"); // シークレットをバイト配列に変換
hmacSha256.init(new SecretKeySpec(secretBytes, 0, secretBytes.length, "HmacSHA256")); // HmacSHA256で初期化
byte[] result = hmacSha256.doFinal(stringToSign.getBytes("UTF-8")); // 署名文字列を暗号化
String sign = Base64.encodeBase64String(result); // 結果をBase64でエンコード

要約すると、stringToSign を UTF-8 を使用してエンコードしてバイト配列を取得します。指定されたアルゴリズムでバイト配列を暗号化します。次に、結果を Base64 を使用してエンコードし、最終的な署名を生成します。

ステップ 3: 署名を追加する

クライアントは、署名検証のために API Gateway に送信される HTTP リクエストに次の 4 つのヘッダーを含める必要があります:

  • x-ca-key: 値は AK/SK 認証設定のアクセスキー (AK) です。

  • x-ca-signature-method: 署名アルゴリズム。有効な値は `HmacSHA256` または `HmacSHA1` です。これはオプションです。デフォルト値は `HmacSHA256` です。

  • x-ca-signature-headers: 署名されたすべてのヘッダーキーのカンマ区切りリスト。これはオプションです。

  • x-ca-signature: 署名。これは必須です。

サーバーでの署名の検証

サーバー側のクライアント署名検証の概要:

  1. 署名対象文字列の抽出: 受信したリクエストからキーデータを抽出して、署名用の文字列を作成します。

  2. AK の抽出: 受信したリクエストから AK を読み取り、それを使用して対応する SK を見つけます。

  3. 署名の計算: 暗号化アルゴリズムと SK を使用して署名対象文字列を暗号化し、署名を生成します。

  4. 署名の検証: 受信したリクエストからクライアントの署名を読み取り、サーバーで生成された署名と比較して一貫性を確認します。

エラー処理

ゲートウェイが署名の検証に失敗した場合、HTTP 応答の X-Ca-Error-Message ヘッダーでサーバー側の署名対象文字列をクライアントに返します。クライアント側の署名対象文字列とサーバー側の署名対象文字列を比較することで、問題を特定できます。クライアントとサーバーからの署名対象文字列の値が同じ場合は、署名計算に使用された SK を確認してください。HTTP ヘッダーには改行を含めることができないため、署名対象文字列の改行は、以下に示すように # に置き換えられます:

X-Ca-Error-Message:  Server StringToSign:`GET#application/json##application/json##X-Ca-Key:200000#X-Ca-Timestamp:1589458000000#/app/v1/config/keys?keys=TEST`

関連するエラーコード

HTTP ステータスコード

エラーメッセージ

原因

401

無効なキー

`x-ca-key` ヘッダーが提供されていないか、無効です。

401

空の署名

`x-ca-signature` ヘッダーが提供されていません。

400

無効な署名

`x-ca-signature` ヘッダーの署名が、サーバーによって計算された署名と一致しません。

400

無効な Content-MD5

`content-md5` ヘッダーが正しくありません。

400

無効な日付

`date` ヘッダーから計算された時間オフセットが、設定された `date_offset` を超えています。

413

リクエスト本文が大きすぎます

リクエストボディが 32 MB のサイズ制限を超えています。

413

ペイロードが大きすぎます

リクエストボディがグローバルの `DownstreamConnectionBufferLimits` 設定を超えています。

403

未承認のコンシューマー

呼び出し元にアクセス権限がありません。

サンプルコード (Go)

go
package main
import (
	"bytes"
	"crypto/hmac"
	"crypto/md5"
	"crypto/sha256"
	"encoding/base64"
	"fmt"
	"io"
	"net/http"
	"strings"
	"time"
)
func generateHMACSignature(toSign string, key string) (string, error) {
	h := hmac.New(sha256.New, []byte(key))
	h.Write([]byte(toSign))
	return base64.StdEncoding.EncodeToString(h.Sum(nil)), nil
}
func test(accessKey, secretKey string) {
	body := `{"hello":"world"}`
	h := md5.New()
	h.Write([]byte(body))
	payload := base64.StdEncoding.EncodeToString(h.Sum(nil))
	headers := map[string]string{
		"accept":                 "application/json",
		"content-type":           "application/json",
		"date":                   time.Now().Format("2006-01-02 15:04:05"),
		"x-ca-key":               accessKey,
		"foo":                    "bar",
		"x-ca-signature-headers": "foo",
		"content-md5":            payload,
	}
	sts := strings.Join([]string{"POST", headers["accept"], headers["content-md5"], headers["content-type"], headers["date"], "foo:bar", "/post"}, "\n")
	fmt.Printf("String to sign is: %s\n", strings.ReplaceAll(sts, "\n", "#"))
	sign, _ := generateHMACSignature(sts, secretKey)
	fmt.Printf("Signed string is: %s\n", sign)
	headers["x-ca-signature"] = sign
	req, _ := http.NewRequest("POST", "http://localhost:8080/post", bytes.NewBufferString(body))
	for k, v := range headers {
		req.Header.Add(k, v)
	}
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		fmt.Println("read body error")
	}
	defer resp.Body.Close()
	fmt.Println("Headers are as follows:")
	for k, v := range resp.Header {
		// 署名計算に失敗した場合、X-Ca-Error-Message レスポンスヘッダーには、サーバーによって計算された署名対象文字列が含まれます。これを使用して問題をトラブルシューティングできます。
		fmt.Printf("  %s: %s\n", k, v)
	}
	respBody, _ := io.ReadAll(resp.Body)
	fmt.Println(string(respBody))
}
func main() {
	test("appKey", "appSecret")
}

APIキー認証

リクエストは、設定された認証情報ソースに基づいて検証されます。このプロセスは API とルートで同様です。次の例ではルートを使用します。

API キーには、主に 3 種類の認証情報ソースがあります:

  1. デフォルトの認証情報ソース: `Authorization: Bearer `。

  2. カスタムヘッダー: ヘッダーパラメーター名を入力します。

  3. カスタムクエリパラメーター: クエリパラメーター名を入力します。

デフォルトの認証情報ソース

次のリクエストがルート `abc` に一致すると仮定します。`Authorization` HTTP リクエストヘッダーに API キーを設定し、プレフィックス `Bearer` を追加します。`Bearer` と API キーの間にスペースがあることに注意してください。

curl  http://xxx.test.com/test -H 'x-api-key: Bearer 2bda943c-ba2b-11ec-ba07-00163e1250b5'

HTTP リクエストヘッダーに API キーを設定する

curl  http://xxx.test.com/test -H 'x-api-key: Bearer 2bda943c-ba2b-11ec-ba07-00163e1250b5'

カスタムヘッダーソース

次のリクエストがルート `abc` に一致し、API キーがカスタム HTTP リクエストヘッダーに設定されていると仮定します。

  • ルートでコンシューマーの認証および権限付与ポリシーが有効になっていない場合、アクセスは 401 エラーで拒否されます。

    curl  http://xxx.test.com/test?apikey=2bda943c-ba2b-11ec-ba07-00163e1250b5
  • ルートでコンシューマーの認証および権限付与ポリシーが有効になっているが、権限が付与されていない場合、403 エラーが返されます。

    curl  http://xxx.test.com/test -H 'x-api-key: 2bda943c-ba2b-11ec-ba07-00163e1250b5'

カスタムクエリパラメーター

次のリクエストがルート `abc` に一致し、API キーが URL クエリパラメーターに設定されていると仮定します。

  • ルートでコンシューマーの認証および権限付与ポリシーが有効になっていない場合、アクセスは 401 エラーで拒否されます。

    curl  http://xxx.test.com/test?apikey=2bda943c-ba2b-11ec-ba07-00163e1250b5
  • ルートでコンシューマーの認証および権限付与ポリシーが有効になっているが、権限が付与されていない場合、403 エラーが返されます。

    curl  http://xxx.test.com/test?apikey=2bda943c-ba2b-11ec-ba07-00163e1250b5

関連するエラーコード

HTTP ステータスコード

エラーメッセージ

原因

401

Key authentication check failed. Multiple API keys were found in the request.

複数の API キーをリクエストできます。

401

Key authentication check failed. No API key was found in the request.

リクエストに API キーが含まれていません。

401

Key authentication check failed. The API key is invalid.

API キーにはリソースにアクセスする権限がありません。

403

Key authentication check failed. The consumer is unauthorized.

コンシューマーに必要なアクセス権限がありません。

参考資料

詳細については、「権限付与管理」をご参照ください。