使用 AWS_IAM 授权对 AWS WebSocket API 网关的请求
Authorise Request to AWS WebSocket API Gateway using AWS_IAM
我已经使用 WebSocket 协议设置了一个 API 网关。在“$connect”路由请求设置中,我选择了 'AWS_IAM' 作为授权方式。在用户通过 Cognito 登录后,Web 应用程序需要连接到此 WebSocket API。然后如何在网络应用程序上授权来自 JavaScript 的 WebSocket API 请求?使用 HTTP API 网关,我可以从访问密钥和 session 令牌生成签名,这些令牌已传递到请求 header。但我无法在 WebSocket 请求中传递 headers。
我已从 AWS 支持部门得到答复。我需要签署 wss URL。因此,不是在 HTTP 请求中设置请求 headers,而是将签名信息传递给查询字符串参数中的 url。签名的 wss URL 看起来像:wss://API_ID.execute-api.region.amazonaws.com/dev?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ACCESSKEY/20200131/region/execute-api/aws4_request&X-Amz-Date=20200131T100233Z&X-Amz-Security-Token=SECURITY_TOKEN&X-Amz-SignedHeaders=host&X-Amz-Signature=SIGNATURE
.
要生成带符号的 URL,我可以使用 @aws-amplify/core 库中的 Signer.signUrl 方法。
这是一些对我有用的 example/pseudo 代码:
使用 AWS Amplify 认证用户:
import { w3cwebsocket as W3CWebSocket } from "websocket"
import { Auth, Signer } from "aws-amplify"
let wsClient: any = null
export const client = async () => {
if (wsClient) return wsClient
if ((await Auth.currentUserInfo()) === null) return wsClient
const credentials = await Auth.currentCredentials()
const accessInfo = {
access_key: credentials.accessKeyId,
secret_key: credentials.secretAccessKey,
session_token: credentials.sessionToken,
}
const wssUrl = "wss://YOUR-API-ID.execute-api.REGION.amazonaws.com/dev"
const signedUrl = Signer.signUrl(wssUrl, accessInfo)
wsClient = new W3CWebSocket(signedUrl)
wsClient.onerror = function () {
console.log("[client]: Connection Error")
}
wsClient.onopen = function () {
console.log("[client]: WebSocket Client Connected")
}
wsClient.onclose = function () {
console.log("[client]: Client Closed")
}
wsClient.onmessage = function (e: any) {
if (typeof e.data === "string") {
console.log("Received: '" + e.data + "'")
}
}
return wsClient
}
然后使用 AWS Cognito 也需要此权限:
{
"Action": ["execute-api:Invoke"],
"Resource": "arn:aws:execute-api:REGION:ACCOUNT-ID-OR-WILDCARD:*/*/$connect",
"Effect": "Allow"
}
我实现了这个签署 AWS 请求 URL 的 Dart 代码。这对于连接到受 IAM 保护的 WebSocket API 网关特别有用。
https://github.com/MohammedNoureldin/aws-url-signer
我知道不鼓励将链接放在答案中,但是将整个 100 行代码复制到这里是没有意义的。
我的实现的用法如下所示:
String getSignedWebSocketUrl(
{String apiId,
String region,
String stage,
String accessKey,
String secretKey,
String sessionToken})
我已经使用 WebSocket 协议设置了一个 API 网关。在“$connect”路由请求设置中,我选择了 'AWS_IAM' 作为授权方式。在用户通过 Cognito 登录后,Web 应用程序需要连接到此 WebSocket API。然后如何在网络应用程序上授权来自 JavaScript 的 WebSocket API 请求?使用 HTTP API 网关,我可以从访问密钥和 session 令牌生成签名,这些令牌已传递到请求 header。但我无法在 WebSocket 请求中传递 headers。
我已从 AWS 支持部门得到答复。我需要签署 wss URL。因此,不是在 HTTP 请求中设置请求 headers,而是将签名信息传递给查询字符串参数中的 url。签名的 wss URL 看起来像:wss://API_ID.execute-api.region.amazonaws.com/dev?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ACCESSKEY/20200131/region/execute-api/aws4_request&X-Amz-Date=20200131T100233Z&X-Amz-Security-Token=SECURITY_TOKEN&X-Amz-SignedHeaders=host&X-Amz-Signature=SIGNATURE
.
要生成带符号的 URL,我可以使用 @aws-amplify/core 库中的 Signer.signUrl 方法。
这是一些对我有用的 example/pseudo 代码:
使用 AWS Amplify 认证用户:
import { w3cwebsocket as W3CWebSocket } from "websocket"
import { Auth, Signer } from "aws-amplify"
let wsClient: any = null
export const client = async () => {
if (wsClient) return wsClient
if ((await Auth.currentUserInfo()) === null) return wsClient
const credentials = await Auth.currentCredentials()
const accessInfo = {
access_key: credentials.accessKeyId,
secret_key: credentials.secretAccessKey,
session_token: credentials.sessionToken,
}
const wssUrl = "wss://YOUR-API-ID.execute-api.REGION.amazonaws.com/dev"
const signedUrl = Signer.signUrl(wssUrl, accessInfo)
wsClient = new W3CWebSocket(signedUrl)
wsClient.onerror = function () {
console.log("[client]: Connection Error")
}
wsClient.onopen = function () {
console.log("[client]: WebSocket Client Connected")
}
wsClient.onclose = function () {
console.log("[client]: Client Closed")
}
wsClient.onmessage = function (e: any) {
if (typeof e.data === "string") {
console.log("Received: '" + e.data + "'")
}
}
return wsClient
}
然后使用 AWS Cognito 也需要此权限:
{
"Action": ["execute-api:Invoke"],
"Resource": "arn:aws:execute-api:REGION:ACCOUNT-ID-OR-WILDCARD:*/*/$connect",
"Effect": "Allow"
}
我实现了这个签署 AWS 请求 URL 的 Dart 代码。这对于连接到受 IAM 保护的 WebSocket API 网关特别有用。
https://github.com/MohammedNoureldin/aws-url-signer
我知道不鼓励将链接放在答案中,但是将整个 100 行代码复制到这里是没有意义的。
我的实现的用法如下所示:
String getSignedWebSocketUrl(
{String apiId,
String region,
String stage,
String accessKey,
String secretKey,
String sessionToken})