To obtain integration sample code, see the Use OpenAPI to debug and integrate server-side APIs document and its Obtain sample code and perform online debugging section on the Alibaba Cloud OpenAPI Portal. This topic also provides ready-to-run code samples.
Sample code overview
|
Programming language |
Integration method |
Credential initialization method |
Sample code |
|
Java |
SDK |
Using the AccessKey of a RAM user |
|
|
Using OIDCRoleArn |
|||
|
Native HTTPS (not recommended) |
Using the AccessKey of a RAM user |
||
|
Using OIDCRoleArn |
Java+SDK+AK
-
Programming language: Java
-
Integration method: SDK
-
Credential initialization method: Using the AccessKey of a RAM user
-
Dependencies:
<dependency> <groupId>com.aliyun</groupId> <artifactId>cloudauth_intl20220809</artifactId> <version>***</version> // To get the latest version, visit the SDK Center: https://next.api.alibabacloud.com/api-tools/sdk/Cloudauth-intl?version=2022-08-09&language=java-tea&tab=primer-doc </dependency> -
Sample code
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 { // Build the client. client = createClient(); } catch (Exception e) { throw new RuntimeException(e); } } public static void main(String[] args) throws Exception { try { // 1. Construct the request parameters. This example uses the Initialize operation. Replace it with the operation you need. InitializeRequest request = new InitializeRequest(); request.setProductCode("***"); request.setMerchantBizId("***"); request.setMerchantUserId("***"); request.setMetaInfo("***"); request.setDocType("********"); request.setAuthorize("*"); // 2. Call the API operation. This example uses the Initialize operation. Replace it with the operation you need. InitializeResponse response = client.initialize(request); // 3. Get the call result. Integer statusCode = response.getStatusCode();// The status code of the call. String code = response.getBody().getCode();// The code of the call. InitializeResponseBody.InitializeResponseBodyResult result = response.getBody().getResult(); // The call result. } catch (Exception e) { // This is for printing and demonstration only. Handle exceptions with care. Do not ignore exceptions in your project. e.printStackTrace(); } } /** * Build the client. * @return * @throws Exception */ public static Client createClient() throws Exception { Config config = new Config(); // Set the AccessKey pair of your account. Do not hard-code the AccessKey pair in your code. We recommend that you retrieve it from environment variables to avoid security vulnerabilities. config.setAccessKeyId("<your access key id>"); config.setAccessKeySecret("<your access key secret>"); // Set the endpoint and regionId. This example uses China (Hong Kong). Replace them with your actual endpoint and region ID. config.setEndpoint("cloudauth-intl.cn-hongkong.aliyuncs.com"); config.setRegionId("cn-hongkong"); return new Client(config); } }
SDK+OIDCRoleArn
-
Programming language: Java
-
Integration method: SDK
-
Credential initialization method: Using OIDCRoleArn
-
Dependencies:
<dependency> <groupId>com.aliyun</groupId> <artifactId>credentials-java</artifactId> <version>***</version> </dependency> // For the latest version of credentials-java, see: https://central.sonatype.com/artifact/com.aliyun/credentials-java <dependency> <groupId>com.aliyun</groupId> <artifactId>cloudauth_intl20220809</artifactId> <version>***</version> // For the latest version of cloudauth_intl20220809, see: https://next.api.alibabacloud.com/api-tools/sdk/Cloudauth-intl?version=2022-08-09&language=java-tea&tab=primer-doc </dependency> -
Sample code
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 { // Build the client. client = createClient(); } catch (Exception e) { throw new RuntimeException(e); } } public static void main(String[] args) throws Exception { try { // 1. Construct the request parameters. This example uses the Initialize operation. Replace it with the operation you need. InitializeRequest request = new InitializeRequest(); request.setProductCode("***"); request.setMerchantBizId("***"); request.setMerchantUserId("***"); request.setMetaInfo("***"); request.setDocType("********"); request.setAuthorize("*"); // 2. Call the API operation. This example uses the Initialize operation. Replace it with the operation you need. InitializeResponse response = client.initialize(request); // 3. Get the call result. Integer statusCode = response.getStatusCode();// The status code. String code = response.getBody().getCode();// The code. InitializeResponseBody.InitializeResponseBodyResult result = response.getBody().getResult();// The detailed response. } catch (Exception e) { // This is for printing and demonstration only. Handle exceptions with care. Do not ignore exceptions in your project. e.printStackTrace(); } } /** * Build the client. * @return * @throws Exception */ public static Client createClient() throws Exception { Config config = new Config(); // Set the credentials. config.setCredential(getCredentialClient()); // Set the endpoint and regionId. This example uses China (Hong Kong). Replace them with your actual endpoint and region 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"); // The Alibaba Cloud Resource Name (ARN) of the RAM role. You can set RoleArn using the ALIBABA_CLOUD_ROLE_ARN environment variable. credentialConfig.setRoleArn("<RoleArn>"); // The ARN of the OIDC provider. You can set OidcProviderArn using the ALIBABA_CLOUD_OIDC_PROVIDER_ARN environment variable. credentialConfig.setOidcProviderArn("<OidcProviderArn>"); // The path of the OIDC token file. You can set OidcTokenFilePath using the ALIBABA_CLOUD_OIDC_TOKEN_FILE environment variable. credentialConfig.setOidcTokenFilePath("<OidcTokenFilePath>"); // The name of the role session. You can set RoleSessionName using the ALIBABA_CLOUD_ROLE_SESSION_NAME environment variable. credentialConfig.setRoleSessionName("<RoleSessionName>"); // Set a more restrictive access policy. This parameter is optional. Example: {"Statement": [{"Action": ["*"],"Effect": "Allow","Resource": ["*"]}],"Version":"1"} credentialConfig.setPolicy("<Policy>"); // Set the session expiration time. credentialConfig.setRoleSessionExpiration(3600); return new com.aliyun.credentials.Client(credentialConfig); } }
Native HTTP+AK
-
Programming language: Java
-
Integration method: Native HTTPS
-
Credential initialization method: Using the AccessKey of a RAM user
-
Dependencies:
<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> -
Sample code
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 { /** * Sample request * @param args * @throws IOException */ public static void main(String[] args) throws IOException { // Set the API operation name. This example uses the Initialize operation. Replace it with the operation you need. String action= "Initialize"; // The version number of the IDV API operation is fixed at 2022-08-09. String version= "2022-08-09"; // Set the endpoint. This example uses China (Hong Kong). Replace it with your actual endpoint. String host = "cloudauth-intl.cn-hongkong.aliyuncs.com"; // Set the AccessKey pair of your account. Do not hard-code the AccessKey pair in your code. We recommend that you retrieve it from environment variables to avoid security vulnerabilities. String accessKey = "<your access key id>"; String accessSecret = "<your access key secret>"; // API request parameters. This example uses the Initialize operation. Replace them with the parameters for the operation you need. Map<String, String> params = new HashMap<>(); params.put("MerchantBizId", "**********"); params.put("ProductCode", "**********"); params.put("MerchantUserId", "**********"); params.put("MetaInfo", "**********"); // 1. Build the service API request. CallRequest callRequest = buildIDVCallRequest(accessKey, accessSecret, action, version, host, params); // 2. Call the IDV service API. String result = callApi(callRequest); // 3. Print the result. System.out.println(result); } /** * Construct the request parameters for calling the IDV service. This is for reference only. Pass in parameters as needed. * @return */ private static CallRequest buildIDVCallRequest(String accessKeyId, String accessKeySecret, String action, String version, String host, Map<String, String> params) { // Request 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"); // Calculate and set the signature. String authorization = getAuthorization(callRequest); callRequest.headers.put("Authorization", authorization); return callRequest; } private static String callApi(CallRequest callRequest) { try { // Send the request using HttpClient. String url = "https://" + callRequest.host + callRequest.canonicalUri; URIBuilder uriBuilder = new URIBuilder(url); // Add request parameters. 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; // Add HTTP request headers. for (Map.Entry<String, String> entry : callRequest.headers.entrySet()) { httpRequest.addHeader(entry.getKey(), String.valueOf(entry.getValue())); } // Send the request. try (CloseableHttpClient httpClient = HttpClients.createDefault(); CloseableHttpResponse response = httpClient.execute(httpRequest)) { String result = EntityUtils.toString(response.getEntity(), "UTF-8"); return result; } catch (IOException e) { // Handle the exception. System.out.println("Failed to send request"); e.printStackTrace(); } } catch (URISyntaxException e) { // Handle the exception. System.out.println("Invalid URI syntax"); e.printStackTrace(); } return null; } /** * This method calculates and generates authorization information based on the HTTP request method, canonical URI, query parameters, and other input. */ private static String getAuthorization(CallRequest callRequest) { try { // Flatten parameters in queryParam that have List or Map values. TreeMap<String, Object> newQueryParam = new TreeMap<>(); processObject(newQueryParam, "", callRequest.queryParam); callRequest.queryParam = newQueryParam; // Step 1: Concatenate a canonical request string. // Request parameters. If the query string is empty, use an empty string as the canonical query string. StringBuilder canonicalQueryString = new StringBuilder(); callRequest.queryParam.entrySet().stream().map(entry -> percentCode(entry.getKey()) + "=" + percentCode(String.valueOf(entry.getValue()))).forEachOrdered(queryPart -> { // If canonicalQueryString is not empty, add an ampersand (&) before the query parameter. if (canonicalQueryString.length() > 0) { canonicalQueryString.append("&"); } canonicalQueryString.append(queryPart); }); // Calculate the hash of the request body. String requestPayload = ""; // Request body. If the request body is empty, such as in a GET request, RequestPayload is a fixed empty string. String hashedRequestPayload = callRequest.body != null ? sha256Hex(callRequest.body) : sha256Hex(requestPayload.getBytes(StandardCharsets.UTF_8)); callRequest.headers.put("x-acs-content-sha256", hashedRequestPayload); // Construct the request headers. Multiple canonical headers are concatenated in ascending order of their lowercase header names. StringBuilder canonicalHeaders = new StringBuilder(); // A list of signed headers. Multiple lowercase header names are sorted in alphabetical order and separated by semicolons (;). 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; // Step 2: Concatenate the string to be signed. String hashedCanonicalRequest = sha256Hex(canonicalRequest.getBytes(StandardCharsets.UTF_8)); // Calculate the hash of the canonical request. String stringToSign = "ACS3-HMAC-SHA256" + "\n" + hashedCanonicalRequest; // Step 3: Calculate the signature. String signature = DatatypeConverter.printHexBinary(hmac256(callRequest.accessKeySecret.getBytes(StandardCharsets.UTF_8), stringToSign)).toLowerCase(); // Step 4: Concatenate the Authorization header. return "ACS3-HMAC-SHA256" + " " + "Credential=" + callRequest.accessKeyId + ",SignedHeaders=" + signedHeaders + ",Signature=" + signature; } catch (Exception e) { // Handle the exception. e.printStackTrace(); throw new RuntimeException("Get authorization failed.", e); } } /** * Recursively process an object to flatten complex objects, such as maps and lists, into key-value pairs. * * @param map The original collection of key-value pairs, which will be recursively updated. * @param key The key being processed. As recursion deepens, the key will contain nested path information. * @param value The value corresponding to the key, which can be a nested Map, List, or other type. */ private static void processObject(Map<String, Object> map, String key, Object value) { // If the value is null, no further processing is needed. if (value == null) { return; } if (key == null) { key = ""; } // If the value is a List, traverse each element in the list and process it recursively. 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<?, ?>) { // If the value is a Map, traverse each key-value pair in the map and process it recursively. Map<?, ?> subMap = (Map<?, ?>) value; for (Map.Entry<?, ?> entry : subMap.entrySet()) { processObject(map, key + "." + entry.getKey().toString(), entry.getValue()); } } else { // For keys that start with a period (.), remove the leading period to maintain key continuity. if (key.startsWith(".")) { key = key.substring(1); } // For values of the byte[] type, convert them to UTF-8 encoded strings. if (value instanceof byte[]) { map.put(key, new String((byte[]) value, StandardCharsets.UTF_8)); } else { // For other types of values, convert them directly to strings. map.put(key, String.valueOf(value)); } } } /** * Generate a Message Authentication Code (MAC) using the HmacSHA256 algorithm. * * @param secretKey The secret key used to generate the MAC. It must be kept confidential. * @param str The message to be authenticated with the MAC. * @return Returns the MAC calculated using the HmacSHA256 algorithm. * @throws Exception Throws an exception if an error occurs during MAC initialization or calculation. */ public static byte[] hmac256(byte[] secretKey, String str) throws Exception { // Instantiate the HmacSHA256 MAC generator. Mac mac = Mac.getInstance("HmacSHA256"); // Create a secret key specification to initialize the MAC generator. SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey, mac.getAlgorithm()); // Initialize the MAC generator. mac.init(secretKeySpec); // Calculate and return the MAC. return mac.doFinal(str.getBytes(StandardCharsets.UTF_8)); } /** * Calculate the SHA-256 hash of a string and return it as a hexadecimal string. * * @param input The byte array to be hashed with SHA-256. * @return The result is a lowercase hexadecimal string. * @throws Exception If an error occurs while getting the SHA-256 message digest instance. */ public static String sha256Hex(byte[] input) throws Exception { // Get a SHA-256 message digest instance. MessageDigest md = MessageDigest.getInstance("SHA-256"); // Calculate the SHA-256 hash of the string s. byte[] d = md.digest(input); // Convert the hash value to a lowercase hexadecimal string and return it. return DatatypeConverter.printHexBinary(d).toLowerCase(); } /** * URL-encode the specified string. * Encodes the string using the UTF-8 character set and replaces specific characters to comply with URL encoding standards. * * @param str The string to be URL-encoded. * @return The encoded string. The plus sign (+) is replaced with "%20", the asterisk (*) with "%2A", and the tilde "%7E" with "~". */ 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 method private final String httpMethod; // The URI of the request. If the resource path is empty, use a forward slash (/) as the CanonicalURI. private final String canonicalUri; // The endpoint. private final String host; // The API operation name. private final String xAcsAction; // The API version. private final String xAcsVersion; // The AccessKey ID. private final String accessKeyId; // The AccessKey secret. private final String accessKeySecret; // The STS token. This parameter is empty for non-STS authentication. private final String securityToken; // The headers. TreeMap<String, String> headers = new TreeMap<>(); // The byte array corresponding to the body parameter. If a request parameter is marked as "in":"body" or "in": "formData" in the metadata, it is placed in the body. byte[] body; // The query parameter. If a request parameter is marked as "in":"query" in the metadata, it is appended to the request 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(); } // Initialize headers. 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")); // Set the time zone for date formatting to 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); } } } }
Native HTTP+OIDCRoleArn
-
Programming language: Java
-
Integration method: Native HTTPS
-
Credential initialization method: Using OIDCRoleArn
-
Dependencies:
<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> -
Sample code
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 { /** * The STS client, used to obtain a Security Token Service (STS) token. */ private static com.aliyun.sts20150401.Client stsClient = null; static { com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config(); // Set the endpoint for the STS service. This example uses Japan (Tokyo). Replace it with your actual endpoint. config.endpoint = "sts.ap-northeast-1.aliyuncs.com"; try { stsClient = new com.aliyun.sts20150401.Client(config); } catch (Exception e) { throw new RuntimeException(e); } } /** * Sample request * @param args * @throws IOException */ public static void main(String[] args) throws IOException { // 1. Obtain a temporary Security Token Service (STS) token based on the OIDC role. The token is valid for a limited period. In a production environment, you can cache and reuse the token within its validity period. AssumeRoleWithOIDCResponseBody.AssumeRoleWithOIDCResponseBodyCredentials credentials = getSTSToken(); // Set the API operation name. This example uses the Initialize operation. Replace it with the operation you need. String action= "Initialize"; // The version number of the IDV API operation is fixed at 2022-08-09. String version= "2022-08-09"; // Set the endpoint. This example uses China (Hong Kong). Replace it with your actual endpoint. String host = "cloudauth-intl.cn-hongkong.aliyuncs.com"; // API request parameters. This is for reference only. Pass in parameters as needed during actual development. Map<String, String> params = new HashMap<>(); params.put("MerchantBizId", "**********"); params.put("ProductCode", "**********"); params.put("MerchantUserId", "**********"); params.put("MetaInfo", "**********"); // 2. Build the service API request. CallRequest callRequest = buildIDVCallRequest(credentials, action, version, host, params); // 3. Call the IDV service API. String result = callApi(callRequest); // 4. Print the result. System.out.println(result); } /** * Construct the request parameters for calling the IDV service. This is for reference only. Pass in parameters as needed. * @return */ private static CallRequest buildIDVCallRequest(AssumeRoleWithOIDCResponseBody.AssumeRoleWithOIDCResponseBodyCredentials credentials, String action, String version, String host, Map<String, String> params) { // Request 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"); // Calculate and set the signature. String authorization = getAuthorization(callRequest); callRequest.headers.put("Authorization", authorization); return callRequest; } /** * Obtain temporary identity credentials (an STS token) by assuming a role. * For more information about STS, see https://www.alibabacloud.com/help/en/ram/product-overview/what-is-sts * This example uses the AssumeRoleWithOIDC method. You can also use other methods such as AssumeRole to obtain temporary identity credentials. For more information, see 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 { // If you copy the code to run, print the API return value yourself. AssumeRoleWithOIDCResponse assumeRoleWithOIDCResponse = stsClient.assumeRoleWithOIDCWithOptions(assumeRoleWithOIDCRequest, runtime); return assumeRoleWithOIDCResponse.body.credentials; } catch (TeaException error) { // This is for printing and demonstration only. Handle exceptions with care. Do not ignore exceptions in your project. // Error message. System.out.println(error.getMessage()); // Diagnosis address. 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); // This is for printing and demonstration only. Handle exceptions with care. Do not ignore exceptions in your project. // Error message. System.out.println(error.getMessage()); // Diagnosis address. 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 { // Send the request using HttpClient. String url = "https://" + callRequest.host + callRequest.canonicalUri; URIBuilder uriBuilder = new URIBuilder(url); // Add request parameters. 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; // Add HTTP request headers. for (Map.Entry<String, String> entry : callRequest.headers.entrySet()) { httpRequest.addHeader(entry.getKey(), String.valueOf(entry.getValue())); } // Send the request. try (CloseableHttpClient httpClient = HttpClients.createDefault(); CloseableHttpResponse response = httpClient.execute(httpRequest)) { String result = EntityUtils.toString(response.getEntity(), "UTF-8"); return result; } catch (IOException e) { // Handle the exception. System.out.println("Failed to send request"); e.printStackTrace(); } } catch (URISyntaxException e) { // Handle the exception. System.out.println("Invalid URI syntax"); e.printStackTrace(); } return null; } /** * This method calculates and generates authorization information based on the HTTP request method, canonical URI, query parameters, and other input. */ private static String getAuthorization(CallRequest callRequest) { try { // Flatten parameters in queryParam that have List or Map values. TreeMap<String, Object> newQueryParam = new TreeMap<>(); processObject(newQueryParam, "", callRequest.queryParam); callRequest.queryParam = newQueryParam; // Step 1: Concatenate a canonical request string. // Request parameters. If the query string is empty, use an empty string as the canonical query string. StringBuilder canonicalQueryString = new StringBuilder(); callRequest.queryParam.entrySet().stream().map(entry -> percentCode(entry.getKey()) + "=" + percentCode(String.valueOf(entry.getValue()))).forEachOrdered(queryPart -> { // If canonicalQueryString is not empty, add an ampersand (&) before the query parameter. if (canonicalQueryString.length() > 0) { canonicalQueryString.append("&"); } canonicalQueryString.append(queryPart); }); // Calculate the hash of the request body. String requestPayload = ""; // Request body. If the request body is empty, such as in a GET request, RequestPayload is a fixed empty string. String hashedRequestPayload = callRequest.body != null ? sha256Hex(callRequest.body) : sha256Hex(requestPayload.getBytes(StandardCharsets.UTF_8)); callRequest.headers.put("x-acs-content-sha256", hashedRequestPayload); // Construct the request headers. Multiple canonical headers are concatenated in ascending order of their lowercase header names. StringBuilder canonicalHeaders = new StringBuilder(); // A list of signed headers. Multiple lowercase header names are sorted in alphabetical order and separated by semicolons (;). 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; // Step 2: Concatenate the string to be signed. String hashedCanonicalRequest = sha256Hex(canonicalRequest.getBytes(StandardCharsets.UTF_8)); // Calculate the hash of the canonical request. String stringToSign = "ACS3-HMAC-SHA256" + "\n" + hashedCanonicalRequest; // Step 3: Calculate the signature. String signature = DatatypeConverter.printHexBinary(hmac256(callRequest.accessKeySecret.getBytes(StandardCharsets.UTF_8), stringToSign)).toLowerCase(); // Step 4: Concatenate the Authorization header. return "ACS3-HMAC-SHA256" + " " + "Credential=" + callRequest.accessKeyId + ",SignedHeaders=" + signedHeaders + ",Signature=" + signature; } catch (Exception e) { // Handle the exception. e.printStackTrace(); throw new RuntimeException("Get authorization failed.", e); } } /** * Recursively process an object to flatten complex objects, such as maps and lists, into key-value pairs. * * @param map The original collection of key-value pairs, which will be recursively updated. * @param key The key being processed. As recursion deepens, the key will contain nested path information. * @param value The value corresponding to the key, which can be a nested Map, List, or other type. */ private static void processObject(Map<String, Object> map, String key, Object value) { // If the value is null, no further processing is needed. if (value == null) { return; } if (key == null) { key = ""; } // If the value is a List, traverse each element in the list and process it recursively. 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<?, ?>) { // If the value is a Map, traverse each key-value pair in the map and process it recursively. Map<?, ?> subMap = (Map<?, ?>) value; for (Map.Entry<?, ?> entry : subMap.entrySet()) { processObject(map, key + "." + entry.getKey().toString(), entry.getValue()); } } else { // For keys that start with a period (.), remove the leading period to maintain key continuity. if (key.startsWith(".")) { key = key.substring(1); } // For values of the byte[] type, convert them to UTF-8 encoded strings. if (value instanceof byte[]) { map.put(key, new String((byte[]) value, StandardCharsets.UTF_8)); } else { // For other types of values, convert them directly to strings. map.put(key, String.valueOf(value)); } } } /** * Generate a Message Authentication Code (MAC) using the HmacSHA256 algorithm. * * @param secretKey The secret key used to generate the MAC. It must be kept confidential. * @param str The message to be authenticated with the MAC. * @return Returns the MAC calculated using the HmacSHA256 algorithm. * @throws Exception Throws an exception if an error occurs during MAC initialization or calculation. */ public static byte[] hmac256(byte[] secretKey, String str) throws Exception { // Instantiate the HmacSHA256 MAC generator. Mac mac = Mac.getInstance("HmacSHA256"); // Create a secret key specification to initialize the MAC generator. SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey, mac.getAlgorithm()); // Initialize the MAC generator. mac.init(secretKeySpec); // Calculate and return the MAC. return mac.doFinal(str.getBytes(StandardCharsets.UTF_8)); } /** * Calculate the SHA-256 hash of a string and return it as a hexadecimal string. * * @param input The byte array to be hashed with SHA-256. * @return The result is a lowercase hexadecimal string. * @throws Exception If an error occurs while getting the SHA-256 message digest instance. */ public static String sha256Hex(byte[] input) throws Exception { // Get a SHA-256 message digest instance. MessageDigest md = MessageDigest.getInstance("SHA-256"); // Calculate the SHA-256 hash of the string s. byte[] d = md.digest(input); // Convert the hash value to a lowercase hexadecimal string and return it. return DatatypeConverter.printHexBinary(d).toLowerCase(); } /** * URL-encode the specified string. * Encodes the string using the UTF-8 character set and replaces specific characters to comply with URL encoding standards. * * @param str The string to be URL-encoded. * @return The encoded string. The plus sign (+) is replaced with "%20", the asterisk (*) with "%2A", and the tilde "%7E" with "~". */ 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 method private final String httpMethod; // The URI of the request. If the resource path is empty, use a forward slash (/) as the CanonicalURI. private final String canonicalUri; // The endpoint. private final String host; // The API operation name. private final String xAcsAction; // The API version. private final String xAcsVersion; // The AccessKey ID. private final String accessKeyId; // The AccessKey secret. private final String accessKeySecret; // The STS token. This parameter is empty for non-STS authentication. private final String securityToken; // The headers. TreeMap<String, String> headers = new TreeMap<>(); // The byte array corresponding to the body parameter. If a request parameter is marked as "in":"body" or "in": "formData" in the metadata, it is placed in the body. byte[] body; // The query parameter. If a request parameter is marked as "in":"query" in the metadata, it is appended to the request 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(); } // Initialize headers. 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")); // Set the time zone for date formatting to 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); } } } }