クラウドネイティブ API Gateway は、グローバル認証、ルートレベルの認証、およびコンシューマーの権限付与をサポートし、権限のあるリクエストのみがサービスにアクセスできるようにします。このトピックでは、クラウドネイティブ API Gateway で認証と権限付与を使用して、コンシューマーがリソースに安全にアクセスできるようにする方法について説明します。
背景情報
グローバル認証と権限付与は、統合ログインなどの B2C (business-to-consumer) シナリオに最適です。対照的に、ルートレベルおよび API レベルのコンシューマー認証は、パートナーに API アクセスを許可するなどの B2B (business-to-business) シナリオ向けに設計されています。
比較 | グローバル認証と承認 | ルート認証 + コンシューマー権限付与 |
シナリオ | 統合ログインや認証など、顧客向け (ToC) のシナリオ。 | パートナーへの API アクセス権の付与など、B2B シナリオ。 |
主な違い | 認証を有効にすると、権限付与も有効になります。 | 認証を有効にした後、権限付与を個別に設定する必要があります。 |
設定エントリポイント | 。 |
|
認証メソッドの設定 (JWT 認証を例として) |
|
|
権限付与メソッドの設定 | 設定を作成するときに、ブラックリストまたはホワイトリストの [ドメイン名] と [パス] のリストを入力します。
|
|
注意事項
コンシューマー認証を有効にすると、ポリシーはすぐに有効になります。ルートまたは API がすでに公開されているが、コンシューマーまたは権限付与ルールが設定されていない場合、すべてのアクセスリクエストはデフォルトで拒否されます。
コンシューマーの認証と権限付与の使用
JWT 認証
JWT 認証フローの概要
クライアントは API Gateway に認証リクエストを送信します。リクエストには通常、エンドユーザーのユーザー名とパスワードが含まれます。
ゲートウェイはリクエストをバックエンドサービスに直接転送します。
バックエンドサービスは、リクエストからユーザー名やパスワードなどの検証情報を読み取って検証します。情報が検証されると、サービスは秘密鍵を使用して標準トークンを生成し、ゲートウェイに返します。
ゲートウェイはトークンを含む応答をクライアントに返します。クライアントはこのトークンをローカルにキャッシュする必要があります。
クライアントはトークンを使用してビジネスリクエストを API Gateway に送信します。
ゲートウェイは、ユーザーが設定した公開鍵を使用してリクエスト内のトークンを検証します。検証に合格すると、リクエストはバックエンドサービスに転送されます。
バックエンドサービスはビジネスロジックを処理し、応答を送信します。
ゲートウェイはビジネス応答をクライアントに返します。
以下のセクションでは、トークンを生成する方法、クライアントがゲートウェイにリクエストを送信する方法、およびゲートウェイが設定された公開鍵を使用してトークンを検証する方法について説明します。
認証サービスでトークンを生成する
次の Java の例は、トークンを生成する方法を示しています。他の言語の場合は、対応するツールを使用してキーペアを生成してください。
Maven プロジェクトを作成し、次の依存関係を追加します:
まず、Maven プロジェクトを作成し、次の依存関係を追加します:
<dependency> <groupId>org.bitbucket.b_c</groupId> <artifactId>jose4j</artifactId> <version>0.7.0</version> </dependency>トークンを生成する方法を選択します。
対称鍵または非対称鍵のいずれかを使用してトークンを生成できます。要件に合ったメソッドを選択してください。
対称鍵を使用してトークンを生成する
コード例:
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 つのステップが含まれます:
サーバーはユーザーリクエストを受信すると、まずトークンが含まれているかどうかを確認します。含まれていない場合、リクエストは 401 エラーで拒否されます。
トークンを含むリクエストの場合、サーバーは設定された JWKS の公開鍵を使用して、トークンが有効で有効期限が切れていないことを確認します。トークンが無効または期限切れの場合、リクエストは 401 エラーで拒否されます。
トークンが有効な場合、サーバーは次に、トークンによって表されるコンシューマーが、リクエストされた API またはルートへのアクセスを許可されているかどうかを確認します。
一般的なエラーコード
HTTP ステータスコード | エラーメッセージ | 原因 |
401 | Jwt missing | リクエストヘッダーに JWT が含まれていません。 |
401 | Jwt expired | JWT の有効期限が切れています。 |
401 | Jwt verification fails | JWT ペイロードの検証に失敗しました。たとえば、`iss` クレームが一致しません。 |
403 | Access Denied | 現在のルートにアクセスする権限がありません。 |
AK/SK (HMAC) 認証
クライアントでの署名の生成
クライアント側の署名生成フロー:
署名対象文字列の抽出: 元のリクエストからキーデータを抽出して、署名用の文字列を作成します。
署名の生成: 暗号化アルゴリズムと設定されたシークレットキー (SK) を使用して署名対象文字列を暗号化し、署名を生成します。
署名の追加: 署名関連のすべてのヘッダーを元の 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: 署名。これは必須です。
サーバーでの署名の検証
サーバー側のクライアント署名検証の概要:
署名対象文字列の抽出: 受信したリクエストからキーデータを抽出して、署名用の文字列を作成します。
AK の抽出: 受信したリクエストから AK を読み取り、それを使用して対応する SK を見つけます。
署名の計算: 暗号化アルゴリズムと SK を使用して署名対象文字列を暗号化し、署名を生成します。
署名の検証: 受信したリクエストからクライアントの署名を読み取り、サーバーで生成された署名と比較して一貫性を確認します。
エラー処理
ゲートウェイが署名の検証に失敗した場合、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 種類の認証情報ソースがあります:
デフォルトの認証情報ソース: `Authorization: Bearer `。
カスタムヘッダー: ヘッダーパラメーター名を入力します。
カスタムクエリパラメーター: クエリパラメーター名を入力します。
デフォルトの認証情報ソース
次のリクエストがルート `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. | コンシューマーに必要なアクセス権限がありません。 |
参考資料
詳細については、「権限付与管理」をご参照ください。