使用Cognito认证连接AWS MQTT3 Websocket时连接意外关闭问题排查
问题描述
通过Websocket连接AWS MQTT 3.1.1,采用Cognito身份认证时触发错误:
Caused by: software.amazon.awssdk.crt.mqtt.MqttException: The connection was closed unexpectedly.
相关实现代码如下:
获取GetCredentialsForIdentityResponse的方法
public GetCredentialsForIdentityResponse getCredentialsForIdentity(AuthenticationResultType accessToken, String identityId) { try (var client = CognitoIdentityClient.builder() .region(Region.of(region)) .build()) { return client.getCredentialsForIdentity( GetCredentialsForIdentityRequest.builder() .identityId(identityId) .logins( Map.of( "cognito-idp.eu-central-1.amazonaws.com/eu-central-1_XGRz3CgoY", accessToken.idToken())) .build()); } }
构建MqttClientConnection的方法
public MqttClientConnection buildConnection(String prefix, String region, String clientId, GetCredentialsForIdentityResponse credentialsForIdentity) { try (var builder = AwsIotMqttConnectionBuilder.newMtlsBuilderFromPath(null, null)) { MqttClientConnectionEvents callbacks = new MqttClientConnectionEvents() { @Override public void onConnectionInterrupted(int errorCode) { log.error("Connection interrupted: " + errorCode + ": " + CRT.awsErrorString(errorCode)); } @Override public void onConnectionResumed(boolean sessionPresent) { log.error("Connection resumed: " + (sessionPresent ? "existing session" : "clean session")); } }; return builder.withEndpoint("%s-ats.iot.%s.amazonaws.com".formatted(prefix, region)) .withWebsockets(true) .withConnectionEventCallbacks(callbacks) .withWebsocketSigningRegion(region) .withClientId(clientId) .withWebsocketCredentialsProvider( new StaticCredentialsProvider.StaticCredentialsProviderBuilder() .withAccessKeyId( credentialsForIdentity.credentials().accessKeyId().getBytes(UTF_8)) .withSecretAccessKey(credentialsForIdentity.credentials().secretKey().getBytes(UTF_8)) .withSessionToken( credentialsForIdentity.credentials().sessionToken().getBytes(UTF_8)) .build()) .build(); } }
错误触发位置
MqttClientConnection connection) throws ExecutionException, InterruptedException { try (connection) { CompletableFuture<Boolean> connected = connection.connect(); boolean sessionPresent = connected.get(); // <--- 错误触发位置 } }
可能的问题分析
1. 连接构建器初始化错误
你使用了MTLS专用的构建器newMtlsBuilderFromPath(null, null),但实际走Websocket协议,应该用Websocket专属构建器:
// 替换原构建器初始化代码 var builder = AwsIotMqttConnectionBuilder.newWebsocketBuilder();
MTLS构建器会残留证书相关配置,即使后续设置withWebsockets(true),也会导致握手逻辑冲突,引发连接意外关闭。
2. IAM权限缺失
确认Cognito身份池绑定的IAM角色包含以下核心权限:
iot:Connect:允许建立MQTT连接iot:Subscribe/iot:Receive(若需订阅主题)iot:Publish(若需发布消息)
同时检查角色的信任策略是否正确关联Cognito身份池,确保权限策略生效。
3. 端点格式错误
验证prefix参数是否匹配AWS IoT控制台"设置"页面的端点前缀。前缀错误会导致连接到无效地址,服务器直接关闭连接。
4. 凭证传递方式问题
StaticCredentialsProvider支持直接传入字符串,无需转字节数组,编码异常可能导致凭证解析失败:
// 修改为直接传入字符串 new StaticCredentialsProvider.StaticCredentialsProviderBuilder() .withAccessKeyId(credentialsForIdentity.credentials().accessKeyId()) .withSecretAccessKey(credentialsForIdentity.credentials().secretKey()) .withSessionToken(credentialsForIdentity.credentials().sessionToken()) .build()
5. Cognito认证有效性问题
- 确认
logins中的Key格式正确:cognito-idp.{region}.amazonaws.com/{userPoolId},同时检查ID Token是否有效、未过期。 - 验证身份池已将对应Cognito用户池配置为身份提供者,且两者处于同一区域。
6. 客户端ID不符合规范
AWS IoT Core限制客户端ID最长128字符,且需符合MQTT 3.1.1格式要求。若客户端ID过长或包含非法字符,会被服务器拒绝连接。
内容的提问来源于stack exchange,提问作者MAGx2
相关产品推荐
相关产品推荐

