「OpenAPI を使用してサーバーサイド API をデバッグおよび統合する」ドキュメントとその「サンプルコードの取得とオンラインデバッグの実行」セクションを使用して、Alibaba Cloud OpenAPI Portal から統合サンプルコードを取得することをお勧めします。このドキュメントでは、直接実行できるコードサンプルも提供しています。
サンプルコードの概要
プログラミング言語 | 統合方法 | 認証情報初期化方法 | サンプルコード |
Java | SDK | RAM ユーザーの AccessKey を使用 | |
OIDCRoleArn を使用 | |||
ネイティブ HTTPS (非推奨) | RAM ユーザーの AccessKey を使用 | ||
OIDCRoleArn を使用 |
Java+SDK+AK
プログラミング言語: Java
統合方法: SDK
認証情報初期化方法: RAM ユーザーの AccessKey を使用
依存関係:
<dependency> <groupId>com.aliyun</groupId> <artifactId>cloudauth_intl20220809</artifactId> <version>***</version> // 最新バージョンを取得するには、SDK センターにアクセスしてください: https://next.api.alibabacloud.com/api-tools/sdk/Cloudauth-intl?version=2022-08-09&language=java-tea&tab=primer-doc </dependency>サンプルコード
import com.aliyun.cloudauth_intl20220809.Client; import com.aliyun.cloudauth_intl20220809.models.InitializeRequest; import com.aliyun.cloudauth_intl20220809.models.InitializeResponse; import com.aliyun.cloudauth_intl20220809.models.InitializeResponseBody; import com.aliyun.teaopenapi.models.Config; public class Sample { private static Client client = null; static { try { // クライアントをビルドします。 client = createClient(); } catch (Exception e) { throw new RuntimeException(e); } } public static void main(String[] args) throws Exception { try { // 1. リクエストパラメーターを構築します。この例では Initialize 操作を使用しています。必要な操作に置き換えてください。 InitializeRequest request = new InitializeRequest(); request.setProductCode("***"); request.setMerchantBizId("***"); request.setMerchantUserId("***"); request.setMetaInfo("***"); request.setDocType("********"); request.setAuthorize("*"); // 2. API 操作を呼び出します。この例では Initialize 操作を使用しています。必要な操作に置き換えてください。 InitializeResponse response = client.initialize(request); // 3. 呼び出し結果を取得します。 Integer statusCode = response.getStatusCode();// 呼び出しの状態コード。 String code = response.getBody().getCode();// 呼び出しのコード。 InitializeResponseBody.InitializeResponseBodyResult result = response.getBody().getResult(); // 呼び出し結果。 } catch (Exception e) { // これは印刷とデモンストレーションのみを目的としています。例外は慎重に処理してください。プロジェクトで例外を無視しないでください。 e.printStackTrace(); } } /** * クライアントをビルドします。 * @return * @throws Exception */ public static Client createClient() throws Exception { Config config = new Config(); // アカウントの AccessKey ペアを設定します。コードに AccessKey ペアをハードコーディングしないでください。セキュリティの脆弱性を避けるために、環境変数から取得することをお勧めします。 config.setAccessKeyId("<your access key id>"); config.setAccessKeySecret("<your access key secret>"); // エンドポイントと regionId を設定します。この例では中国 (香港) を使用しています。実際の エンドポイントとリージョン ID に置き換えてください。 config.setEndpoint("cloudauth-intl.cn-hongkong.aliyuncs.com"); config.setRegionId("cn-hongkong"); return new Client(config); } }
SDK+OIDCRoleArn
プログラミング言語: Java
統合方法: SDK
認証情報初期化方法: OIDCRoleArn を使用
依存関係:
<dependency> <groupId>com.aliyun</groupId> <artifactId>credentials-java</artifactId> <version>***</version> </dependency> // credentials-java の最新バージョンについては、次を参照してください: https://central.sonatype.com/artifact/com.aliyun/credentials-java <dependency> <groupId>com.aliyun</groupId> <artifactId>cloudauth_intl20220809</artifactId> <version>***</version> // cloudauth_intl20220809 の最新バージョンについては、次を参照してください: https://next.api.alibabacloud.com/api-tools/sdk/Cloudauth-intl?version=2022-08-09&language=java-tea&tab=primer-doc </dependency>サンプルコード
import com.aliyun.cloudauth_intl20220809.Client; import com.aliyun.cloudauth_intl20220809.models.InitializeRequest; import com.aliyun.cloudauth_intl20220809.models.InitializeResponse; import com.aliyun.cloudauth_intl20220809.models.InitializeResponseBody; import com.aliyun.teaopenapi.models.Config; public class Sample { private static Client client = null; static { try { // クライアントをビルドします。 client = createClient(); } catch (Exception e) { throw new RuntimeException(e); } } public static void main(String[] args) throws Exception { try { // 1. リクエストパラメーターを構築します。この例では Initialize 操作を使用しています。必要な操作に置き換えてください。 InitializeRequest request = new InitializeRequest(); request.setProductCode("***"); request.setMerchantBizId("***"); request.setMerchantUserId("***"); request.setMetaInfo("***"); request.setDocType("********"); request.setAuthorize("*"); // 2. API 操作を呼び出します。この例では Initialize 操作を使用しています。必要な操作に置き換えてください。 InitializeResponse response = client.initialize(request); // 3. 呼び出し結果を取得します。 Integer statusCode = response.getStatusCode();// 状態コード。 String code = response.getBody().getCode();// コード。 InitializeResponseBody.InitializeResponseBodyResult result = response.getBody().getResult();// 詳細な応答。 } catch (Exception e) { // これは印刷とデモンストレーションのみを目的としています。例外は慎重に処理してください。プロジェクトで例外を無視しないでください。 e.printStackTrace(); } } /** * クライアントをビルドします。 * @return * @throws Exception */ public static Client createClient() throws Exception { Config config = new Config(); // 認証情報を設定します。 config.setCredential(getCredentialClient()); // エンドポイントと regionId を設定します。この例では中国 (香港) を使用しています。実際の エンドポイントとリージョン ID に置き換えてください。 config.setEndpoint("cloudauth-intl.cn-hongkong.aliyuncs.com"); config.setRegionId("cn-hongkong"); return new Client(config); } public static com.aliyun.credentials.Client getCredentialClient() throws Exception { com.aliyun.credentials.models.Config credentialConfig = new com.aliyun.credentials.models.Config(); credentialConfig.setType("oidc_role_arn"); // RAM ロールの Alibaba Cloud リソースネーム (ARN)。ALIBABA_CLOUD_ROLE_ARN 環境変数を使用して RoleArn を設定できます。 credentialConfig.setRoleArn("<RoleArn>"); // OIDC プロバイダーの ARN。ALIBABA_CLOUD_OIDC_PROVIDER_ARN 環境変数を使用して OidcProviderArn を設定できます。 credentialConfig.setOidcProviderArn("<OidcProviderArn>"); // OIDC トークンファイルのパス。ALIBABA_CLOUD_OIDC_TOKEN_FILE 環境変数を使用して OidcTokenFilePath を設定できます。 credentialConfig.setOidcTokenFilePath("<OidcTokenFilePath>"); // ロールセッションの名前。ALIBABA_CLOUD_ROLE_SESSION_NAME 環境変数を使用して RoleSessionName を設定できます。 credentialConfig.setRoleSessionName("<RoleSessionName>"); // より制限の厳しいアクセスポリシーを設定します。このパラメーターはオプションです。例: {"Statement": [{"Action": ["*"],"Effect": "Allow","Resource": ["*"]}],"Version":"1"} credentialConfig.setPolicy("<Policy>"); // セッションの有効期限を設定します。 credentialConfig.setRoleSessionExpiration(3600); return new com.aliyun.credentials.Client(credentialConfig); } }
ネイティブ HTTP+AK
プログラミング言語: Java
統合方法: ネイティブ HTTPS
認証情報初期化方法: RAM ユーザーの AccessKey を使用
依存関係:
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.13</version> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.9.0</version> </dependency>サンプルコード
import com.google.gson.Gson; import com.google.gson.GsonBuilder; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.utils.URIBuilder; import org.apache.http.entity.ByteArrayEntity; import org.apache.http.entity.ContentType; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import javax.xml.bind.DatatypeConverter; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URISyntaxException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.text.SimpleDateFormat; import java.util.*; public class Sample { /** * サンプルリクエスト * @param args * @throws IOException */ public static void main(String[] args) throws IOException { // API 操作名を設定します。この例では Initialize 操作を使用しています。必要な操作に置き換えてください。 String action= "Initialize"; // IDV API 操作のバージョン番号は 2022-08-09 に固定されています。 String version= "2022-08-09"; // エンドポイントを設定します。この例では中国 (香港) を使用しています。実際のエンドポイントに置き換えてください。 String host = "cloudauth-intl.cn-hongkong.aliyuncs.com"; // アカウントの AccessKey ペアを設定します。コードに AccessKey ペアをハードコーディングしないでください。セキュリティの脆弱性を避けるために、環境変数から取得することをお勧めします。 String accessKey = "<your access key id>"; String accessSecret = "<your access key secret>"; // API リクエストパラメーター。この例では Initialize 操作を使用しています。必要な操作のパラメーターに置き換えてください。 Map<String, String> params = new HashMap<>(); params.put("MerchantBizId", "**********"); params.put("ProductCode", "**********"); params.put("MerchantUserId", "**********"); params.put("MetaInfo", "**********"); // 1. サービス API リクエストをビルドします。 CallRequest callRequest = buildIDVCallRequest(accessKey, accessSecret, action, version, host, params); // 2. IDV サービス API を呼び出します。 String result = callApi(callRequest); // 3. 結果を出力します。 System.out.println(result); } /** * IDV サービスを呼び出すためのリクエストパラメーターを構築します。これは参照用です。必要に応じてパラメーターを渡してください。 * @return */ private static CallRequest buildIDVCallRequest(String accessKeyId, String accessKeySecret, String action, String version, String host, Map<String, String> params) { // リクエスト URL。 String httpMethod = "POST"; String canonicalUri = "/"; CallRequest callRequest = new CallRequest(httpMethod, canonicalUri, host, action, version, accessKeyId, accessKeySecret, null); Gson gson = (new GsonBuilder()).disableHtmlEscaping().create(); callRequest.body = gson.toJson(params).getBytes(StandardCharsets.UTF_8); callRequest.headers.put("content-type", "application/json"); // 署名を計算して設定します。 String authorization = getAuthorization(callRequest); callRequest.headers.put("Authorization", authorization); return callRequest; } private static String callApi(CallRequest callRequest) { try { // HttpClient を使用してリクエストを送信します。 String url = "https://" + callRequest.host + callRequest.canonicalUri; URIBuilder uriBuilder = new URIBuilder(url); // リクエストパラメーターを追加します。 for (Map.Entry<String, Object> entry : callRequest.queryParam.entrySet()) { uriBuilder.addParameter(entry.getKey(), String.valueOf(entry.getValue())); } HttpUriRequest httpRequest; HttpPost httpPost = new HttpPost(uriBuilder.build()); if (callRequest.body != null) { httpPost.setEntity(new ByteArrayEntity(callRequest.body, ContentType.create(callRequest.headers.get("content-type")))); } httpRequest = httpPost; // HTTP リクエストヘッダーを追加します。 for (Map.Entry<String, String> entry : callRequest.headers.entrySet()) { httpRequest.addHeader(entry.getKey(), String.valueOf(entry.getValue())); } // リクエストを送信します。 try (CloseableHttpClient httpClient = HttpClients.createDefault(); CloseableHttpResponse response = httpClient.execute(httpRequest)) { String result = EntityUtils.toString(response.getEntity(), "UTF-8"); return result; } catch (IOException e) { // 例外を処理します。 System.out.println("リクエストの送信に失敗しました"); e.printStackTrace(); } } catch (URISyntaxException e) { // 例外を処理します。 System.out.println("無効な URI 構文"); e.printStackTrace(); } return null; } /** * このメソッドは、HTTP リクエストメソッド、正規 URI、クエリパラメーター、およびその他の入力に基づいて権限付与情報を計算および生成します。 */ private static String getAuthorization(CallRequest callRequest) { try { // List または Map の値を持つ queryParam のパラメーターをフラット化します。 TreeMap<String, Object> newQueryParam = new TreeMap<>(); processObject(newQueryParam, "", callRequest.queryParam); callRequest.queryParam = newQueryParam; // ステップ 1: 正規リクエスト文字列を連結します。 // リクエストパラメーター。クエリ文字列が空の場合、空の文字列を正規クエリ文字列として使用します。 StringBuilder canonicalQueryString = new StringBuilder(); callRequest.queryParam.entrySet().stream().map(entry -> percentCode(entry.getKey()) + "=" + percentCode(String.valueOf(entry.getValue()))).forEachOrdered(queryPart -> { // canonicalQueryString が空でない場合、クエリパラメーターの前にアンパサンド (&) を追加します。 if (canonicalQueryString.length() > 0) { canonicalQueryString.append("&"); } canonicalQueryString.append(queryPart); }); // リクエストボディのハッシュを計算します。 String requestPayload = ""; // リクエストボディ。GET リクエストのようにリクエストボディが空の場合、RequestPayload は固定の空文字列です。 String hashedRequestPayload = callRequest.body != null ? sha256Hex(callRequest.body) : sha256Hex(requestPayload.getBytes(StandardCharsets.UTF_8)); callRequest.headers.put("x-acs-content-sha256", hashedRequestPayload); // リクエストヘッダーを構築します。複数の正規ヘッダーは、小文字のヘッダー名の昇順で連結されます。 StringBuilder canonicalHeaders = new StringBuilder(); // 署名付きヘッダーのリスト。複数の小文字のヘッダー名はアルファベット順にソートされ、セミコロン (;) で区切られます。 StringBuilder signedHeadersSb = new StringBuilder(); callRequest.headers.entrySet().stream().filter(entry -> entry.getKey().toLowerCase().startsWith("x-acs-") || "host".equalsIgnoreCase(entry.getKey()) || "content-type".equalsIgnoreCase(entry.getKey())).sorted(Map.Entry.comparingByKey()).forEach(entry -> { String lowerKey = entry.getKey().toLowerCase(); String value = String.valueOf(entry.getValue()).trim(); canonicalHeaders.append(lowerKey).append(":").append(value).append("\n"); signedHeadersSb.append(lowerKey).append(";"); }); String signedHeaders = signedHeadersSb.substring(0, signedHeadersSb.length() - 1); String canonicalRequest = callRequest.httpMethod + "\n" + callRequest.canonicalUri + "\n" + canonicalQueryString + "\n" + canonicalHeaders + "\n" + signedHeaders + "\n" + hashedRequestPayload; // ステップ 2: 署名する文字列を連結します。 String hashedCanonicalRequest = sha256Hex(canonicalRequest.getBytes(StandardCharsets.UTF_8)); // 正規リクエストのハッシュを計算します。 String stringToSign = "ACS3-HMAC-SHA256" + "\n" + hashedCanonicalRequest; // ステップ 3: 署名を計算します。 String signature = DatatypeConverter.printHexBinary(hmac256(callRequest.accessKeySecret.getBytes(StandardCharsets.UTF_8), stringToSign)).toLowerCase(); // ステップ 4: Authorization ヘッダーを連結します。 return "ACS3-HMAC-SHA256" + " " + "Credential=" + callRequest.accessKeyId + ",SignedHeaders=" + signedHeaders + ",Signature=" + signature; } catch (Exception e) { // 例外を処理します。 e.printStackTrace(); throw new RuntimeException("Get authorization failed.", e); } } /** * オブジェクトを再帰的に処理して、マップやリストなどの複雑なオブジェクトをキーと値のペアにフラット化します。 * * @param map 再帰的に更新されるキーと値のペアの元のコレクション。 * @param key 処理中のキー。再帰が深くなるにつれて、キーにはネストされたパス情報が含まれます。 * @param value キーに対応する値。ネストされた Map、List、またはその他の型にすることができます。 */ private static void processObject(Map<String, Object> map, String key, Object value) { // 値が null の場合、それ以上の処理は必要ありません。 if (value == null) { return; } if (key == null) { key = ""; } // 値が List の場合、リスト内の各要素を走査し、再帰的に処理します。 if (value instanceof List<?>) { List<?> list = (List<?>) value; for (int i = 0; i < list.size(); ++i) { processObject(map, key + "." + (i + 1), list.get(i)); } } else if (value instanceof Map<?, ?>) { // 値が Map の場合、マップ内の各キーと値のペアを走査し、再帰的に処理します。 Map<?, ?> subMap = (Map<?, ?>) value; for (Map.Entry<?, ?> entry : subMap.entrySet()) { processObject(map, key + "." + entry.getKey().toString(), entry.getValue()); } } else { // ピリオド (.) で始まるキーの場合、先頭のピリオドを削除してキーの連続性を維持します。 if (key.startsWith(".")) { key = key.substring(1); } // byte[] 型の値の場合、UTF-8 エンコードされた文字列に変換します。 if (value instanceof byte[]) { map.put(key, new String((byte[]) value, StandardCharsets.UTF_8)); } else { // 他の型の値の場合、直接文字列に変換します。 map.put(key, String.valueOf(value)); } } } /** * HmacSHA256 アルゴリズムを使用してメッセージ認証コード (MAC) を生成します。 * * @param secretKey MAC の生成に使用されるシークレットキー。機密に保つ必要があります。 * @param str MAC で認証されるメッセージ。 * @return HmacSHA256 アルゴリズムを使用して計算された MAC を返します。 * @throws Exception MAC の初期化または計算中にエラーが発生した場合に例外をスローします。 */ public static byte[] hmac256(byte[] secretKey, String str) throws Exception { // HmacSHA256 MAC ジェネレーターをインスタンス化します。 Mac mac = Mac.getInstance("HmacSHA256"); // MAC ジェネレーターを初期化するためのシークレットキースペックを作成します。 SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey, mac.getAlgorithm()); // MAC ジェネレーターを初期化します。 mac.init(secretKeySpec); // MAC を計算して返します。 return mac.doFinal(str.getBytes(StandardCharsets.UTF_8)); } /** * 文字列の SHA-256 ハッシュを計算し、16 進数文字列として返します。 * * @param input SHA-256 でハッシュ化されるバイト配列。 * @return 結果は小文字の 16 進数文字列です。 * @throws Exception SHA-256 メッセージダイジェストインスタンスの取得中にエラーが発生した場合。 */ public static String sha256Hex(byte[] input) throws Exception { // SHA-256 メッセージダイジェストインスタンスを取得します。 MessageDigest md = MessageDigest.getInstance("SHA-256"); // 文字列 s の SHA-256 ハッシュを計算します。 byte[] d = md.digest(input); // ハッシュ値を小文字の 16 進数文字列に変換して返します。 return DatatypeConverter.printHexBinary(d).toLowerCase(); } /** * 指定された文字列を URL エンコードします。 * UTF-8 文字セットを使用して文字列をエンコードし、URL エンコーディング標準に準拠するように特定の文字を置き換えます。 * * @param str URL エンコードされる文字列。 * @return エンコードされた文字列。プラス記号 (+) は "%20" に、アスタリスク (*) は "%2A" に、チルダ "%7E" は "~" に置き換えられます。 */ public static String percentCode(String str) { if (str == null) { throw new IllegalArgumentException("The input string cannot be null."); } try { return URLEncoder.encode(str, "UTF-8").replace("+", "%20").replace("*", "%2A").replace("%7E", "~"); } catch (UnsupportedEncodingException e) { throw new RuntimeException("UTF-8 encoding is not supported.", e); } } private static class CallRequest { // HTTP メソッド private final String httpMethod; // リクエストの URI。リソースパスが空の場合、スラッシュ (/) を CanonicalURI として使用します。 private final String canonicalUri; // エンドポイント。 private final String host; // API 操作名。 private final String xAcsAction; // API バージョン。 private final String xAcsVersion; // AccessKey ID。 private final String accessKeyId; // AccessKey Secret。 private final String accessKeySecret; // STS トークン。このパラメーターは非 STS 認証では空です。 private final String securityToken; // ヘッダー。 TreeMap<String, String> headers = new TreeMap<>(); // body パラメーターに対応するバイト配列。メタデータでリクエストパラメーターが "in":"body" または "in": "formData" とマークされている場合、それは body に配置されます。 byte[] body; // クエリパラメーター。メタデータでリクエストパラメーターが "in":"query" とマークされている場合、それはリクエスト URL に追加されます。 TreeMap<String, Object> queryParam = new TreeMap<>(); public CallRequest(String httpMethod, String canonicalUri, String host, String xAcsAction, String xAcsVersion, String accessKeyId, String accessKeySecret, String securityToken) { this.httpMethod = httpMethod; this.canonicalUri = canonicalUri; this.host = host; this.xAcsAction = xAcsAction; this.xAcsVersion = xAcsVersion; this.accessKeyId = accessKeyId; this.accessKeySecret = accessKeySecret; this.securityToken = securityToken; initHeader(); } // ヘッダーを初期化します。 private void initHeader() { headers.put("host", host); headers.put("x-acs-action", xAcsAction); headers.put("x-acs-version", xAcsVersion); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); sdf.setTimeZone(new SimpleTimeZone(0, "GMT")); // 日付フォーマットのタイムゾーンを GMT に設定します。 headers.put("x-acs-date", sdf.format(new Date())); headers.put("x-acs-signature-nonce", UUID.randomUUID().toString()); if (securityToken != null) { headers.put("x-acs-security-token", securityToken); } } } }
ネイティブ HTTP+OIDCRoleArn
プログラミング言語: Java
統合方法: ネイティブ HTTPS
認証情報初期化方法: OIDCRoleArn を使用
依存関係:
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.13</version> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.9.0</version> </dependency> <dependency> <groupId>com.aliyun</groupId> <artifactId>sts20150401</artifactId> <version>1.1.7</version> </dependency>サンプルコード
import com.aliyun.sts20150401.models.AssumeRoleWithOIDCResponse; import com.aliyun.sts20150401.models.AssumeRoleWithOIDCResponseBody; import com.aliyun.tea.TeaException; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import org.apache.http.client.methods.*; import org.apache.http.client.utils.URIBuilder; import org.apache.http.entity.ByteArrayEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import org.apache.http.entity.ContentType; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import javax.xml.bind.DatatypeConverter; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URISyntaxException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.text.SimpleDateFormat; import java.util.*; public class Sample { /** * STS クライアント。セキュリティトークンサービス (STS) トークンを取得するために使用されます。 */ private static com.aliyun.sts20150401.Client stsClient = null; static { com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config(); // STS サービスのエンドポイントを設定します。この例では日本 (東京) を使用しています。実際のエンドポイントに置き換えてください。 config.endpoint = "sts.ap-northeast-1.aliyuncs.com"; try { stsClient = new com.aliyun.sts20150401.Client(config); } catch (Exception e) { throw new RuntimeException(e); } } /** * サンプルリクエスト * @param args * @throws IOException */ public static void main(String[] args) throws IOException { // 1. OIDC ロールに基づいて一時的なセキュリティトークンサービス (STS) トークンを取得します。トークンは限られた期間のみ有効です。本番環境では、有効期間内にトークンをキャッシュして再利用できます。 AssumeRoleWithOIDCResponseBody.AssumeRoleWithOIDCResponseBodyCredentials credentials = getSTSToken(); // API 操作名を設定します。この例では Initialize 操作を使用しています。必要な操作に置き換えてください。 String action= "Initialize"; // IDV API 操作のバージョン番号は 2022-08-09 に固定されています。 String version= "2022-08-09"; // エンドポイントを設定します。この例では中国 (香港) を使用しています。実際のエンドポイントに置き換えてください。 String host = "cloudauth-intl.cn-hongkong.aliyuncs.com"; // API リクエストパラメーター。これは参照用です。実際の開発中に必要に応じてパラメーターを渡してください。 Map<String, String> params = new HashMap<>(); params.put("MerchantBizId", "**********"); params.put("ProductCode", "**********"); params.put("MerchantUserId", "**********"); params.put("MetaInfo", "**********"); // 2. サービス API リクエストをビルドします。 CallRequest callRequest = buildIDVCallRequest(credentials, action, version, host, params); // 3. IDV サービス API を呼び出します。 String result = callApi(callRequest); // 4. 結果を出力します。 System.out.println(result); } /** * IDV サービスを呼び出すためのリクエストパラメーターを構築します。これは参照用です。必要に応じてパラメーターを渡してください。 * @return */ private static CallRequest buildIDVCallRequest(AssumeRoleWithOIDCResponseBody.AssumeRoleWithOIDCResponseBodyCredentials credentials, String action, String version, String host, Map<String, String> params) { // リクエスト URL。 String httpMethod = "POST"; String canonicalUri = "/"; CallRequest callRequest = new CallRequest(httpMethod, canonicalUri, host, action, version, credentials.getAccessKeyId(), credentials.getAccessKeySecret(), credentials.getSecurityToken()); Gson gson = (new GsonBuilder()).disableHtmlEscaping().create(); callRequest.body = gson.toJson(params).getBytes(StandardCharsets.UTF_8); callRequest.headers.put("content-type", "application/json"); // 署名を計算して設定します。 String authorization = getAuthorization(callRequest); callRequest.headers.put("Authorization", authorization); return callRequest; } /** * ロールを偽装して一時的な認証情報 (STS トークン) を取得します。 * 詳細については、「https://www.alibabacloud.com/help/en/ram/product-overview/what-is-sts」をご参照ください。 * この例では AssumeRoleWithOIDC メソッドを使用しています。AssumeRole などの他のメソッドを使用して一時的な認証情報を取得することもできます。詳細については、「https://www.alibabacloud.com/help/en/ram/developer-reference/api-sts-2015-04-01-dir-role-assuming」をご参照ください。 * @return */ public static AssumeRoleWithOIDCResponseBody.AssumeRoleWithOIDCResponseBodyCredentials getSTSToken() { com.aliyun.sts20150401.models.AssumeRoleWithOIDCRequest assumeRoleWithOIDCRequest = new com.aliyun.sts20150401.models.AssumeRoleWithOIDCRequest() .setOIDCProviderArn("***") .setRoleArn("***") .setDurationSeconds(3600L) .setOIDCToken("***") .setRoleSessionName("***"); com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions(); try { // コードをコピーして実行する場合、API の戻り値を自分で出力してください。 AssumeRoleWithOIDCResponse assumeRoleWithOIDCResponse = stsClient.assumeRoleWithOIDCWithOptions(assumeRoleWithOIDCRequest, runtime); return assumeRoleWithOIDCResponse.body.credentials; } catch (TeaException error) { // これは印刷とデモンストレーションのみを目的としています。例外は慎重に処理してください。プロジェクトで例外を無視しないでください。 // エラーメッセージ。 System.out.println(error.getMessage()); // 診断アドレス。 System.out.println(error.getData().get("Recommend")); com.aliyun.teautil.Common.assertAsString(error.message); throw new RuntimeException(error); } catch (Exception _error) { TeaException error = new TeaException(_error.getMessage(), _error); // これは印刷とデモンストレーションのみを目的としています。例外は慎重に処理してください。プロジェクトで例外を無視しないでください。 // エラーメッセージ。 System.out.println(error.getMessage()); // 診断アドレス。 System.out.println(error.getData().get("Recommend")); com.aliyun.teautil.Common.assertAsString(error.message); throw new RuntimeException(error); } } private static String callApi(CallRequest callRequest) { try { // HttpClient を使用してリクエストを送信します。 String url = "https://" + callRequest.host + callRequest.canonicalUri; URIBuilder uriBuilder = new URIBuilder(url); // リクエストパラメーターを追加します。 for (Map.Entry<String, Object> entry : callRequest.queryParam.entrySet()) { uriBuilder.addParameter(entry.getKey(), String.valueOf(entry.getValue())); } HttpUriRequest httpRequest; HttpPost httpPost = new HttpPost(uriBuilder.build()); if (callRequest.body != null) { httpPost.setEntity(new ByteArrayEntity(callRequest.body, ContentType.create(callRequest.headers.get("content-type")))); } httpRequest = httpPost; // HTTP リクエストヘッダーを追加します。 for (Map.Entry<String, String> entry : callRequest.headers.entrySet()) { httpRequest.addHeader(entry.getKey(), String.valueOf(entry.getValue())); } // リクエストを送信します。 try (CloseableHttpClient httpClient = HttpClients.createDefault(); CloseableHttpResponse response = httpClient.execute(httpRequest)) { String result = EntityUtils.toString(response.getEntity(), "UTF-8"); return result; } catch (IOException e) { // 例外を処理します。 System.out.println("リクエストの送信に失敗しました"); e.printStackTrace(); } } catch (URISyntaxException e) { // 例外を処理します。 System.out.println("無効な URI 構文"); e.printStackTrace(); } return null; } /** * このメソッドは、HTTP リクエストメソッド、正規 URI、クエリパラメーター、およびその他の入力に基づいて権限付与情報を計算および生成します。 */ private static String getAuthorization(CallRequest callRequest) { try { // List または Map の値を持つ queryParam のパラメーターをフラット化します。 TreeMap<String, Object> newQueryParam = new TreeMap<>(); processObject(newQueryParam, "", callRequest.queryParam); callRequest.queryParam = newQueryParam; // ステップ 1: 正規リクエスト文字列を連結します。 // リクエストパラメーター。クエリ文字列が空の場合、空の文字列を正規クエリ文字列として使用します。 StringBuilder canonicalQueryString = new StringBuilder(); callRequest.queryParam.entrySet().stream().map(entry -> percentCode(entry.getKey()) + "=" + percentCode(String.valueOf(entry.getValue()))).forEachOrdered(queryPart -> { // canonicalQueryString が空でない場合、クエリパラメーターの前にアンパサンド (&) を追加します。 if (canonicalQueryString.length() > 0) { canonicalQueryString.append("&"); } canonicalQueryString.append(queryPart); }); // リクエストボディのハッシュを計算します。 String requestPayload = ""; // リクエストボディ。GET リクエストのようにリクエストボディが空の場合、RequestPayload は固定の空文字列です。 String hashedRequestPayload = callRequest.body != null ? sha256Hex(callRequest.body) : sha256Hex(requestPayload.getBytes(StandardCharsets.UTF_8)); callRequest.headers.put("x-acs-content-sha256", hashedRequestPayload); // リクエストヘッダーを構築します。複数の正規ヘッダーは、小文字のヘッダー名の昇順で連結されます。 StringBuilder canonicalHeaders = new StringBuilder(); // 署名付きヘッダーのリスト。複数の小文字のヘッダー名はアルファベット順にソートされ、セミコロン (;) で区切られます。 StringBuilder signedHeadersSb = new StringBuilder(); callRequest.headers.entrySet().stream().filter(entry -> entry.getKey().toLowerCase().startsWith("x-acs-") || "host".equalsIgnoreCase(entry.getKey()) || "content-type".equalsIgnoreCase(entry.getKey())).sorted(Map.Entry.comparingByKey()).forEach(entry -> { String lowerKey = entry.getKey().toLowerCase(); String value = String.valueOf(entry.getValue()).trim(); canonicalHeaders.append(lowerKey).append(":").append(value).append("\n"); signedHeadersSb.append(lowerKey).append(";"); }); String signedHeaders = signedHeadersSb.substring(0, signedHeadersSb.length() - 1); String canonicalRequest = callRequest.httpMethod + "\n" + callRequest.canonicalUri + "\n" + canonicalQueryString + "\n" + canonicalHeaders + "\n" + signedHeaders + "\n" + hashedRequestPayload; // ステップ 2: 署名する文字列を連結します。 String hashedCanonicalRequest = sha256Hex(canonicalRequest.getBytes(StandardCharsets.UTF_8)); // 正規リクエストのハッシュを計算します。 String stringToSign = "ACS3-HMAC-SHA256" + "\n" + hashedCanonicalRequest; // ステップ 3: 署名を計算します。 String signature = DatatypeConverter.printHexBinary(hmac256(callRequest.accessKeySecret.getBytes(StandardCharsets.UTF_8), stringToSign)).toLowerCase(); // ステップ 4: Authorization ヘッダーを連結します。 return "ACS3-HMAC-SHA256" + " " + "Credential=" + callRequest.accessKeyId + ",SignedHeaders=" + signedHeaders + ",Signature=" + signature; } catch (Exception e) { // 例外を処理します。 e.printStackTrace(); throw new RuntimeException("Get authorization failed.", e); } } /** * オブジェクトを再帰的に処理して、マップやリストなどの複雑なオブジェクトをキーと値のペアにフラット化します。 * * @param map 再帰的に更新されるキーと値のペアの元のコレクション。 * @param key 処理中のキー。再帰が深くなるにつれて、キーにはネストされたパス情報が含まれます。 * @param value キーに対応する値。ネストされた Map、List、またはその他の型にすることができます。 */ private static void processObject(Map<String, Object> map, String key, Object value) { // 値が null の場合、それ以上の処理は必要ありません。 if (value == null) { return; } if (key == null) { key = ""; } // 値が List の場合、リスト内の各要素を走査し、再帰的に処理します。 if (value instanceof List<?>) { List<?> list = (List<?>) value; for (int i = 0; i < list.size(); ++i) { processObject(map, key + "." + (i + 1), list.get(i)); } } else if (value instanceof Map<?, ?>) { // 値が Map の場合、マップ内の各キーと値のペアを走査し、再帰的に処理します。 Map<?, ?> subMap = (Map<?, ?>) value; for (Map.Entry<?, ?> entry : subMap.entrySet()) { processObject(map, key + "." + entry.getKey().toString(), entry.getValue()); } } else { // ピリオド (.) で始まるキーの場合、先頭のピリオドを削除してキーの連続性を維持します。 if (key.startsWith(".")) { key = key.substring(1); } // byte[] 型の値の場合、UTF-8 エンコードされた文字列に変換します。 if (value instanceof byte[]) { map.put(key, new String((byte[]) value, StandardCharsets.UTF_8)); } else { // 他の型の値の場合、直接文字列に変換します。 map.put(key, String.valueOf(value)); } } } /** * HmacSHA256 アルゴリズムを使用してメッセージ認証コード (MAC) を生成します。 * * @param secretKey MAC の生成に使用されるシークレットキー。機密に保つ必要があります。 * @param str MAC で認証されるメッセージ。 * @return HmacSHA256 アルゴリズムを使用して計算された MAC を返します。 * @throws Exception MAC の初期化または計算中にエラーが発生した場合に例外をスローします。 */ public static byte[] hmac256(byte[] secretKey, String str) throws Exception { // HmacSHA256 MAC ジェネレーターをインスタンス化します。 Mac mac = Mac.getInstance("HmacSHA256"); // MAC ジェネレーターを初期化するためのシークレットキースペックを作成します。 SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey, mac.getAlgorithm()); // MAC ジェネレーターを初期化します。 mac.init(secretKeySpec); // MAC を計算して返します。 return mac.doFinal(str.getBytes(StandardCharsets.UTF_8)); } /** * 文字列の SHA-256 ハッシュを計算し、16 進数文字列として返します。 * * @param input SHA-256 でハッシュ化されるバイト配列。 * @return 結果は小文字の 16 進数文字列です。 * @throws Exception SHA-256 メッセージダイジェストインスタンスの取得中にエラーが発生した場合。 */ public static String sha256Hex(byte[] input) throws Exception { // SHA-256 メッセージダイジェストインスタンスを取得します。 MessageDigest md = MessageDigest.getInstance("SHA-256"); // 文字列 s の SHA-256 ハッシュを計算します。 byte[] d = md.digest(input); // ハッシュ値を小文字の 16 進数文字列に変換して返します。 return DatatypeConverter.printHexBinary(d).toLowerCase(); } /** * 指定された文字列を URL エンコードします。 * UTF-8 文字セットを使用して文字列をエンコードし、URL エンコーディング標準に準拠するように特定の文字を置き換えます。 * * @param str URL エンコードされる文字列。 * @return エンコードされた文字列。プラス記号 (+) は "%20" に、アスタリスク (*) は "%2A" に、チルダ "%7E" は "~" に置き換えられます。 */ public static String percentCode(String str) { if (str == null) { throw new IllegalArgumentException("The input string cannot be null."); } try { return URLEncoder.encode(str, "UTF-8").replace("+", "%20").replace("*", "%2A").replace("%7E", "~"); } catch (UnsupportedEncodingException e) { throw new RuntimeException("UTF-8 encoding is not supported.", e); } } private static class CallRequest { // HTTP メソッド private final String httpMethod; // リクエストの URI。リソースパスが空の場合、スラッシュ (/) を CanonicalURI として使用します。 private final String canonicalUri; // エンドポイント。 private final String host; // API 操作名。 private final String xAcsAction; // API バージョン。 private final String xAcsVersion; // AccessKey ID。 private final String accessKeyId; // AccessKey Secret。 private final String accessKeySecret; // STS トークン。このパラメーターは非 STS 認証では空です。 private final String securityToken; // ヘッダー。 TreeMap<String, String> headers = new TreeMap<>(); // body パラメーターに対応するバイト配列。メタデータでリクエストパラメーターが "in":"body" または "in": "formData" とマークされている場合、それは body に配置されます。 byte[] body; // クエリパラメーター。メタデータでリクエストパラメーターが "in":"query" とマークされている場合、それはリクエスト URL に追加されます。 TreeMap<String, Object> queryParam = new TreeMap<>(); public CallRequest(String httpMethod, String canonicalUri, String host, String xAcsAction, String xAcsVersion, String accessKeyId, String accessKeySecret, String securityToken) { this.httpMethod = httpMethod; this.canonicalUri = canonicalUri; this.host = host; this.xAcsAction = xAcsAction; this.xAcsVersion = xAcsVersion; this.accessKeyId = accessKeyId; this.accessKeySecret = accessKeySecret; this.securityToken = securityToken; initHeader(); } // ヘッダーを初期化します。 private void initHeader() { headers.put("host", host); headers.put("x-acs-action", xAcsAction); headers.put("x-acs-version", xAcsVersion); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); sdf.setTimeZone(new SimpleTimeZone(0, "GMT")); // 日付フォーマットのタイムゾーンを GMT に設定します。 headers.put("x-acs-date", sdf.format(new Date())); headers.put("x-acs-signature-nonce", UUID.randomUUID().toString()); if (securityToken != null) { headers.put("x-acs-security-token", securityToken); } } } }