Beim Aufruf der Bedrock-API unter Verwendung von Java-Code mit SDK ist ein Fehler aufgetreten, bei dem die Signatur nichJava

Java-Forum
Guest
 Beim Aufruf der Bedrock-API unter Verwendung von Java-Code mit SDK ist ein Fehler aufgetreten, bei dem die Signatur nich

Post by Guest »

Ich versuche, die AWS Bedrock API mit Java aufzurufen, ohne das AWS SDK zu verwenden. Ich erhalte jedoch immer wieder die Fehlermeldung 403 Forbidden mit der Meldung „Signatur stimmt nicht überein“. Die gleiche Anfrage funktioniert perfekt in Python.
Unten ist mein Java-Code:

Code: Select all

@Service
public class AnthropicServiceImpl {

private static final String AWS_ACCESS_KEY_ID = "accesskeyid";
private static final String AWS_SECRET_ACCESS_KEY = "secretkey";

private static final String METHOD = "POST";
private static final String SERVICE = "bedrock";
private static final String REGION = "us-east-1";
private static final String ALGORITHM = "AWS4-HMAC-SHA256";
private static final String HOST = "bedrock-runtime.us-east-1.amazonaws.com";
private static final String ENDPOINT_PATH = "/model/anthropic.claude-3-haiku-20240307-v1:0/invoke";

public static void main(String[] args) throws Exception {
// Use TreeMap to ensure consistent ordering of headers
TreeMap headers = new TreeMap();

String payload = "{"
+ "\"anthropic_version\": \"bedrock-2023-05-31\","
+ "\"max_tokens\": 512,"
+ "\"messages\": ["
+ "    {"
+ "        \"role\": \"user\","
+ "        \"content\": ["
+ "            {"
+ "                \"type\": \"text\","
+ "                \"text\": \"What is java\""
+ "            }"
+ "        ]"
+ "    }"
+ "]"
+ "}";

// Create a datetime object for signing
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'", Locale.US);
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
String amzDate = dateFormat.format(new Date());
String dateStamp = amzDate.substring(0, 8);

// Calculate payload hash
String payloadHash = sha256Hex(payload);
String contentLength = String.valueOf(payload.getBytes(StandardCharsets.UTF_8).length);

// Add headers to TreeMap to ensure consistent ordering
headers.put("accept", "application/json");
headers.put("content-length", contentLength);
headers.put("content-type", "application/json");
headers.put("host", HOST);
headers.put("x-amz-content-sha256", payloadHash);
headers.put("x-amz-date", amzDate);
headers.put("x-amzn-bedrock-save", "true");

// Build canonical headers and signed headers string
StringBuilder canonicalHeadersBuilder = new StringBuilder();
StringBuilder signedHeadersBuilder = new StringBuilder();

boolean first = true;
for (String key : headers.keySet()) {
canonicalHeadersBuilder.append(key.toLowerCase())
.append(":")
.append(headers.get(key).trim())
.append("\n");

if (!first) {
signedHeadersBuilder.append(";");
}
signedHeadersBuilder.append(key.toLowerCase());
first = false;
}

String canonicalHeaders = canonicalHeadersBuilder.toString();
String signedHeaders = signedHeadersBuilder.toString();

// Create canonical request
String canonicalRequest = METHOD + "\n"
+ ENDPOINT_PATH + "\n"
+ "\n"  // Empty query string
+ canonicalHeaders + "\n"
+ signedHeaders + "\n"
+ payloadHash;

// Create string to sign
String credentialScope = String.format("%s/%s/%s/aws4_request", dateStamp, REGION, SERVICE);
String stringToSign = ALGORITHM + "\n"
+ amzDate + "\n"
+ credentialScope + "\n"
+ sha256Hex(canonicalRequest);

System.out.println("Canonical Request:\n" + canonicalRequest);
System.out.println("\nString to Sign:\n"  + stringToSign);

// Calculate signature
byte[] signingKey = getSignatureKey(AWS_SECRET_ACCESS_KEY, dateStamp, REGION, SERVICE);
String signature = hmacSha256Hex(signingKey, stringToSign);

// Create authorization header
String authorizationHeader = String.format("%s Credential=%s/%s, SignedHeaders=%s, Signature=%s",
ALGORITHM, AWS_ACCESS_KEY_ID, credentialScope, signedHeaders, signature);

// Make the request
URL url = new URL("https://" + HOST + ENDPOINT_PATH);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod(METHOD);

// Set all headers from our TreeMap
for (String key : headers.keySet()) {
conn.setRequestProperty(key, headers.get(key));
}
conn.setRequestProperty("Authorization", authorizationHeader);

// Print request details for debugging
System.out.println("\nAuthorization Header:\n" + authorizationHeader);
System.out.println("\nPayload Hash: " + payloadHash);

// Send payload
try (OutputStream os = conn.getOutputStream()) {
byte[] input = payload.getBytes(StandardCharsets.UTF_8);
os.write(input, 0, input.length);
}

// Get response
int responseCode = conn.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
String response = new String(conn.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
System.out.println("Response: " + response);
} else {
System.out.println("Error: " + responseCode + " " + conn.getResponseMessage());
String errorResponse = new String(conn.getErrorStream().readAllBytes(), StandardCharsets.UTF_8);
System.out.println("Error details: " + errorResponse);
}
}

private static byte[] getSignatureKey(String key, String dateStamp, String regionName, String serviceName) {
try {
byte[] kSecret = ("AWS4"  + key).getBytes(StandardCharsets.UTF_8);
byte[] kDate = hmacSha256(kSecret, dateStamp);
byte[] kRegion = hmacSha256(kDate, regionName);
byte[] kService = hmacSha256(kRegion, serviceName);
return hmacSha256(kService, "aws4_request");
} catch (Exception e) {
throw new RuntimeException("Error calculating signing key", e);
}
}

private static byte[] hmacSha256(byte[] key, String data) throws NoSuchAlgorithmException, InvalidKeyException {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(key, "HmacSHA256"));
return mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
}

private static String hmacSha256Hex(byte[] key, String data) {
try {
return bytesToHex(hmacSha256(key, data));
} catch (Exception e) {
throw new RuntimeException("Error calculating HMAC", e);
}
}

private static String sha256Hex(String data) throws NoSuchAlgorithmException {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(data.getBytes(StandardCharsets.UTF_8));
return bytesToHex(hash);
}

private static String bytesToHex(byte[] bytes) {
StringBuilder result = new StringBuilder();
for (byte b : bytes) {
result.append(String.format("%02x", b));
}
return result.toString();
}
}
Der funktionierende Python-Code ist:

Code: Select all

import boto3
import json
from botocore.awsrequest import AWSRequest
from botocore.auth import SigV4Auth
from botocore.credentials import Credentials

# AWS credentials
access_key = "access key"
secret_key = "secret key"

# Service and region
service = "bedrock"
region = "us-east-1"

# Request details
url = "https://bedrock-runtime.us-east-1.amazonaws.com/model/anthropic.claude-3-haiku-20240307-v1:0/invoke"
payload = {
"messages": [{"role": "user", "content": "What is python?"}],
"temperature": 0.5,
"top_p": 0.9,
"max_tokens": 512,
"anthropic_version": "bedrock-2023-05-31",  # Set version to a valid one
}
headers = {
"Accept": "application/json",
"X-Amzn-Bedrock-Save": "true",
"Content-Type": "application/json",
}

# Create AWS request
request = AWSRequest(method="POST", url=url, data=json.dumps(payload), headers=headers)
credentials = Credentials(access_key, secret_key)
SigV4Auth(credentials, service, region).add_auth(request)

# Create an HTTP client manually using botocore for sending the request
import botocore.session

# Create a botocore session
session = botocore.session.get_session()
client = session.create_client(service, region_name=region, aws_access_key_id=access_key, aws_secret_access_key=secret_key)

# Send the prepared request using the client
http_session = client._endpoint.http_session
response = http_session.send(request.prepare())

# Debugging
print("Payload Sent:")
print(json.dumps(payload, indent=4))
print("\nResponse:")
print(response.text)
Gesendete Nutzlast:

Code: Select all

{
"messages": [
{
"role": "user",
"content": "What is python?"
}
],
"temperature": 0.5,
"top_p": 0.9,
"max_tokens": 512,
"anthropic_version": "bedrock-2023-05-31"
}
Antwort:

Code: Select all

{"id":"msg_bdrk_01YDAcio1xXTfXMkL6xhheNz","type":"message","role":"assistant","model":"claude-3-haiku-20240307","content":[{"type":"text","text":"Python is a high-level, general-purpose programming language."}],"stop_reason":"end_turn","stop_sequence":null,"usage":{"input_tokens":11,"output_tokens":318}}
Die gleiche Anfrage funktioniert perfekt in Python.

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post