连接到 websocket 以实时消费 amazon chime API
Connect to websocket to consuming amazon chime API in real time
我想使用 Amazon Chime API 扩展我用 JavaFX 编写的软件以使用其消息传递。我知道有 JS SDK 可以毫无问题地建立消息传递 websocket 会话。但是在 java SDK 中没有相关的 classes。所以我想使用 STOMP 库来使用 websocket 端点。
当时我正在努力做出正确的 request, namely with signing AWS request(计算 X-AMZ-Signature)
根据 post,我正在尝试计算正确的 X-AMZ-Signature 请求参数。这是 class:
@Slf4j
@Service
public class Aws4Signer {
private final static String REQUEST_CONTENT_TYPE = "application/json";
private final static String AUTH_ALGORITHM = "AWS4-HMAC-SHA256";
private final static String REQUEST_METHOD = "GET";
@Data
class AuthenticationData {
@NonNull
String timestamp;
@NonNull
String date;
@NonNull
String authorizationHeader;
}
private AppConfig appConfig = new AppConfig();
/**
* Gets the timestamp in YYYYMMDD'T'HHMMSS'Z' format, which is the required
* format for AWS4 signing request headers and credential string
*
* @param dateTime
* an OffsetDateTime object representing the UTC time of current
* signing request
* @return the formatted timestamp string
*
* @see <a href=
* "https://docs.aws.amazon.com/general/latest/gr/sigv4-signed-request-examples.html">
* Examples of the Complete Version 4 Signing Process (Python)</a>
*/
public String getTimeStamp(OffsetDateTime dateTime) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'");
String formatDateTime = dateTime.format(formatter);
return formatDateTime;
}
/**
* Gets the date string in yyyyMMdd format, which is required to build the
* credential scope string
*
* @return the formatted date string
*/
public String getDate(OffsetDateTime dateTime) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
String formatDateTime = dateTime.format(formatter);
return formatDateTime;
}
public byte[] generateAws4SigningKey(String timestamp) {
String secretKey = appConfig.getAwsAuthConfig().getSecretKey();
String regionName = appConfig.getAwsAuthConfig().getServiceRegion();
String serviceName = appConfig.getAwsAuthConfig().getServiceName();
byte[] signatureKey = null;
try {
signatureKey = Aws4SignatureKeyGenerator.generateSignatureKey(secretKey, timestamp, regionName,
serviceName);
} catch (Exception e) {
log.error("An error has ocurred when generate signature key: " + e, e);
}
return signatureKey;
}
/**
* Builds an {@link AuthenticationData} object containing the timestamp, date,
* payload hash and the AWS4 signature
* <p>
*
* The signing logic was translated from the Python implementation, see this
* link for more details: <a href=
* "https://docs.aws.amazon.com/general/latest/gr/sigv4-signed-request-examples.html">Examples
* of the Complete Version 4 Signing Process (Python)</a>
*
* @param target
* @param requestBody
*
* @return
* @throws NoSuchAlgorithmException
* @throws UnsupportedEncodingException
* @throws InvalidKeyException
* @throws SignatureException
* @throws IllegalStateException
*
*/
public AuthenticationData buildAuthorizationData() throws NoSuchAlgorithmException,
UnsupportedEncodingException, InvalidKeyException, SignatureException, IllegalStateException {
log.info("predict - start");
// Starting building the lengthy signing data
AwsAuthConfig awsAuthConfig = appConfig.getAwsAuthConfig();
String payloadHash = Hmac.getSha256Hash(requestBody);
OffsetDateTime now = OffsetDateTime.now(ZoneOffset.UTC);
String timestamp = getTimeStamp(now);
String date = getDate(now);
// Step 1 is to define the verb (GET, POST, etc.) -- already done by defining
// constant REQUEST_METHOD
// Step 2: Create canonical URI--the part of the URI from domain to query
// string (use '/' if no path)
String canonical_uri = "/connect";
// Step 3: Create the canonical query string. In this example, request
// parameters are passed in the body of the request and the query string
// is blank.
String canonical_querystring = buildCanonicalQueryString();
// Step 4: Create the canonical headers. Header names must be trimmed
// and lowercase, and sorted in code point order from low to high.
// Note that there is a trailing \n.
String canonical_headers = "content-type:" + REQUEST_CONTENT_TYPE + "\n"
+ "host:" + awsAuthConfig.getServiceHost() + "\n"
+ "x-amz-date:" + timestamp + "\n";
String signed_headers = "content-type;host;x-amz-date";
log.debug("canonical_headers : {}", canonical_headers);
String canonical_request = REQUEST_METHOD + "\n" + canonical_uri + "\n" + canonical_querystring + "\n"
+ canonical_headers + "\n" + signed_headers;
log.debug("canonical_request : {}", canonical_request);
String credential_scope = date + "/" + awsAuthConfig.getServiceRegion() + "/" + awsAuthConfig.getServiceName()
+ "/" + "aws4_request";
String canonical_request_hash = Hmac.getSha256Hash(canonical_request);
log.debug("canonical_request_hash : {}", canonical_request_hash);
String string_to_sign = AUTH_ALGORITHM + "\n" + timestamp + "\n" + credential_scope + "\n"
+ canonical_request_hash;
log.debug("string_to_sign : {}", string_to_sign);
byte[] sigKey = generateAws4SigningKey(date);
String signature = Hmac.calculateHMAC(string_to_sign, sigKey, Hmac.HMAC_SHA256);
String authorization_header = AUTH_ALGORITHM + " " + "Credential=" + awsAuthConfig.getAccessKey() + "/"
+ credential_scope + ", " + "SignedHeaders=" + signed_headers + ", " + "Signature=" + signature;
log.debug("authorization_header : {}", authorization_header);
return new AuthenticationData(timestamp, date, authorization_header);
}
private String buildCanonicalQueryString() {
String canonicalRequest = REQUEST_METHOD + "\n" +
"/connect" + "\n" +
"X-Amz-Algorithm=AWS4-HMAC-SHA256\n" +
"&X-Amz-Credential=MYACCESKEY%2F"+ getDate(OffsetDateTime.now()) + "%2Fus-east-1%2Fchime%2Faws4_request\n" +
"&X-Amz-Date=" + getTimeStamp(OffsetDateTime.now()) +"\n" +
"&X-Amz-Expires=10\n" +
"&X-Amz-SignedHeaders=host\n" +
"&sessionId=" + UUID.randomUUID() +"\n" +
"&userArn=" + "MYUSERARN";
return canonicalRequest;
}
}
提供的信息
- 主机:node001.ue1.ws-messaging.chime.aws
- 服务名称:编钟
- 区域:us-east-1
它生成了签名,我正在尝试通过邮递员使用它,但邮递员无法连接到端点 node001。ue1.ws-messaging.chime.aws/connect,只是说 'connect ETIMEDOUT 54.162.103.101:80'.
我是亚马逊的新手,所以对我来说有点难。你能说我哪里错了吗?
感谢任何帮助!
为签名 code 编写了完整的工作 URL 以连接到 chime websocket。希望这会对某人有所帮助!
我想使用 Amazon Chime API 扩展我用 JavaFX 编写的软件以使用其消息传递。我知道有 JS SDK 可以毫无问题地建立消息传递 websocket 会话。但是在 java SDK 中没有相关的 classes。所以我想使用 STOMP 库来使用 websocket 端点。
当时我正在努力做出正确的 request, namely with signing AWS request(计算 X-AMZ-Signature)
根据 post,我正在尝试计算正确的 X-AMZ-Signature 请求参数。这是 class:
@Slf4j
@Service
public class Aws4Signer {
private final static String REQUEST_CONTENT_TYPE = "application/json";
private final static String AUTH_ALGORITHM = "AWS4-HMAC-SHA256";
private final static String REQUEST_METHOD = "GET";
@Data
class AuthenticationData {
@NonNull
String timestamp;
@NonNull
String date;
@NonNull
String authorizationHeader;
}
private AppConfig appConfig = new AppConfig();
/**
* Gets the timestamp in YYYYMMDD'T'HHMMSS'Z' format, which is the required
* format for AWS4 signing request headers and credential string
*
* @param dateTime
* an OffsetDateTime object representing the UTC time of current
* signing request
* @return the formatted timestamp string
*
* @see <a href=
* "https://docs.aws.amazon.com/general/latest/gr/sigv4-signed-request-examples.html">
* Examples of the Complete Version 4 Signing Process (Python)</a>
*/
public String getTimeStamp(OffsetDateTime dateTime) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'");
String formatDateTime = dateTime.format(formatter);
return formatDateTime;
}
/**
* Gets the date string in yyyyMMdd format, which is required to build the
* credential scope string
*
* @return the formatted date string
*/
public String getDate(OffsetDateTime dateTime) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
String formatDateTime = dateTime.format(formatter);
return formatDateTime;
}
public byte[] generateAws4SigningKey(String timestamp) {
String secretKey = appConfig.getAwsAuthConfig().getSecretKey();
String regionName = appConfig.getAwsAuthConfig().getServiceRegion();
String serviceName = appConfig.getAwsAuthConfig().getServiceName();
byte[] signatureKey = null;
try {
signatureKey = Aws4SignatureKeyGenerator.generateSignatureKey(secretKey, timestamp, regionName,
serviceName);
} catch (Exception e) {
log.error("An error has ocurred when generate signature key: " + e, e);
}
return signatureKey;
}
/**
* Builds an {@link AuthenticationData} object containing the timestamp, date,
* payload hash and the AWS4 signature
* <p>
*
* The signing logic was translated from the Python implementation, see this
* link for more details: <a href=
* "https://docs.aws.amazon.com/general/latest/gr/sigv4-signed-request-examples.html">Examples
* of the Complete Version 4 Signing Process (Python)</a>
*
* @param target
* @param requestBody
*
* @return
* @throws NoSuchAlgorithmException
* @throws UnsupportedEncodingException
* @throws InvalidKeyException
* @throws SignatureException
* @throws IllegalStateException
*
*/
public AuthenticationData buildAuthorizationData() throws NoSuchAlgorithmException,
UnsupportedEncodingException, InvalidKeyException, SignatureException, IllegalStateException {
log.info("predict - start");
// Starting building the lengthy signing data
AwsAuthConfig awsAuthConfig = appConfig.getAwsAuthConfig();
String payloadHash = Hmac.getSha256Hash(requestBody);
OffsetDateTime now = OffsetDateTime.now(ZoneOffset.UTC);
String timestamp = getTimeStamp(now);
String date = getDate(now);
// Step 1 is to define the verb (GET, POST, etc.) -- already done by defining
// constant REQUEST_METHOD
// Step 2: Create canonical URI--the part of the URI from domain to query
// string (use '/' if no path)
String canonical_uri = "/connect";
// Step 3: Create the canonical query string. In this example, request
// parameters are passed in the body of the request and the query string
// is blank.
String canonical_querystring = buildCanonicalQueryString();
// Step 4: Create the canonical headers. Header names must be trimmed
// and lowercase, and sorted in code point order from low to high.
// Note that there is a trailing \n.
String canonical_headers = "content-type:" + REQUEST_CONTENT_TYPE + "\n"
+ "host:" + awsAuthConfig.getServiceHost() + "\n"
+ "x-amz-date:" + timestamp + "\n";
String signed_headers = "content-type;host;x-amz-date";
log.debug("canonical_headers : {}", canonical_headers);
String canonical_request = REQUEST_METHOD + "\n" + canonical_uri + "\n" + canonical_querystring + "\n"
+ canonical_headers + "\n" + signed_headers;
log.debug("canonical_request : {}", canonical_request);
String credential_scope = date + "/" + awsAuthConfig.getServiceRegion() + "/" + awsAuthConfig.getServiceName()
+ "/" + "aws4_request";
String canonical_request_hash = Hmac.getSha256Hash(canonical_request);
log.debug("canonical_request_hash : {}", canonical_request_hash);
String string_to_sign = AUTH_ALGORITHM + "\n" + timestamp + "\n" + credential_scope + "\n"
+ canonical_request_hash;
log.debug("string_to_sign : {}", string_to_sign);
byte[] sigKey = generateAws4SigningKey(date);
String signature = Hmac.calculateHMAC(string_to_sign, sigKey, Hmac.HMAC_SHA256);
String authorization_header = AUTH_ALGORITHM + " " + "Credential=" + awsAuthConfig.getAccessKey() + "/"
+ credential_scope + ", " + "SignedHeaders=" + signed_headers + ", " + "Signature=" + signature;
log.debug("authorization_header : {}", authorization_header);
return new AuthenticationData(timestamp, date, authorization_header);
}
private String buildCanonicalQueryString() {
String canonicalRequest = REQUEST_METHOD + "\n" +
"/connect" + "\n" +
"X-Amz-Algorithm=AWS4-HMAC-SHA256\n" +
"&X-Amz-Credential=MYACCESKEY%2F"+ getDate(OffsetDateTime.now()) + "%2Fus-east-1%2Fchime%2Faws4_request\n" +
"&X-Amz-Date=" + getTimeStamp(OffsetDateTime.now()) +"\n" +
"&X-Amz-Expires=10\n" +
"&X-Amz-SignedHeaders=host\n" +
"&sessionId=" + UUID.randomUUID() +"\n" +
"&userArn=" + "MYUSERARN";
return canonicalRequest;
}
}
提供的信息
- 主机:node001.ue1.ws-messaging.chime.aws
- 服务名称:编钟
- 区域:us-east-1
它生成了签名,我正在尝试通过邮递员使用它,但邮递员无法连接到端点 node001。ue1.ws-messaging.chime.aws/connect,只是说 'connect ETIMEDOUT 54.162.103.101:80'.
我是亚马逊的新手,所以对我来说有点难。你能说我哪里错了吗?
感谢任何帮助!
为签名 code 编写了完整的工作 URL 以连接到 chime websocket。希望这会对某人有所帮助!