javascript - 通过 Cognito Identity Pool 验证的用户的 MQTT 连接

标签 javascript amazon-web-services mqtt aws-sdk

很快:我有一个联合身份池,它具有用于未经身份验证和经过身份验证的访问的 Angular 色。我对未经身份验证的访问没有任何问题。但是当涉及到经过身份验证的访问时,用户登录就好了,但我对经过身份验证的用户的 Angular 色并没有得到实际应用。


我有一个 s3 存储桶,其中包含通过 MQTT 进行通信的简单 index.html 和 index.js 文件。

经过身份验证和未经身份验证的用户的策略现在看起来完全相同,并且相当宽松(当然这不是用于生产的方式,但我只是试图让它以任何方式工作到目前为止)。因此,这两个策略如下所示:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "*",
            "Resource": "*"
        }
    ]
}

并且在 index.js 中,我可以作为未验证用户建立 MQTT 连接,如下所示:

var region = 'eu-west-1';
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
  IdentityPoolId: 'my-identity-pool-id',
});
AWS.config.credentials.clearCachedId();
AWS.config.credentials.get(function(err) {
  console.log('accessKeyId:', AWS.config.credentials.accessKeyId);
  if(err) {
    console.log(err);
    return;
  }
  var requestUrl = SigV4Utils.getSignedUrl(
    'wss',
    'data.iot.' + region + '.amazonaws.com',
    '/mqtt',
    'iotdevicegateway',
    region,
    AWS.config.credentials.accessKeyId,
    AWS.config.credentials.secretAccessKey,
    AWS.config.credentials.sessionToken
  );

  initClient(requestUrl);
});

initClient()只是通过Paho建立MQTT连接:

function initClient(requestUrl) {
  var clientId = String(Math.random()).replace('.', '');
  var rpcId = "smart_heater_" + String(Math.random()).replace('.', '');
  var client = new Paho.MQTT.Client(requestUrl, clientId);
  var connectOptions = {
    onSuccess: function () {
      console.log('connected');
      // Now I can call client.subscribe(...) or client.send(...)
    },
    useSSL: true,
    timeout: 3,
    mqttVersion: 4,
    onFailure: function (err) {
      console.error('connect failed', err);
    }
  };
  client.connect(connectOptions);

  client.onMessageArrived = function (message) {
    console.log("msg arrived: " +  message);
  };
}

它工作得很好:connected 被打印到控制台,我实际上可以发送/订阅。

现在,我正在尝试对经过身份验证的用户执行相同的操作。为此,我添加了 Cognito 用户池,在那里创建了一个用户,创建了一个“应用程序”,将身份验证提供程序“Cognito”添加到我的身份池(具有适当的用户池 ID 和应用程序客户端 ID),并且身份验证本身工作正常:用户登录。代码如下所示:

var region = 'eu-west-1';
var poolData = {
  UserPoolId: 'eu-west-1_XXXXXXXXX',
  ClientId: 'ZZZZZZZZZZZZZZZZZZZZZZZZZ',
};
var userPool = new AWSCognito.CognitoIdentityServiceProvider.CognitoUserPool(poolData);

var authenticationData = {
  Username: 'myusername',
  Password: 'mypassword',
};
var authenticationDetails = new AWSCognito.CognitoIdentityServiceProvider.AuthenticationDetails(authenticationData);
var userData = {
  Username: 'myusername',
  Pool: userPool
};
var cognitoUser = new AWSCognito.CognitoIdentityServiceProvider.CognitoUser(userData);
cognitoUser.authenticateUser(authenticationDetails, {
  onSuccess: function (result) {
    console.log('result:', result);
    console.log('access token: ' + result.getAccessToken().getJwtToken());

    var myUserPoolId = 'eu-west-1_XXXXXXXXX';
    console.log('You are now logged in.');

    // Add the User's Id Token to the Cognito credentials login map.
    var logins = {};
    logins['cognito-idp.' + region + '.amazonaws.com/' + myUserPoolId] = result.getIdToken().getJwtToken();

    AWS.config.credentials.params.Logins = logins;
    // finally, expire the credentials so we refresh on the next request
    AWS.config.credentials.expired = true;

    //call refresh method in order to authenticate user and get new temp credentials
    AWS.config.credentials.refresh((error) => {
      if (error) {
        console.error(error);
      } else {
        console.log('Successfully logged!');
        console.log('accessKeyId:', AWS.config.credentials.accessKeyId);

        var requestUrl = SigV4Utils.getSignedUrl(
          'wss',
          'data.iot.' + region + '.amazonaws.com',
          '/mqtt',
          'iotdevicegateway',
          region,
          AWS.config.credentials.accessKeyId,
          AWS.config.credentials.secretAccessKey,
          AWS.config.credentials.sessionToken
        );

        initClient(requestUrl);
      }
    });
  },

  onFailure: function (err) {
    alert(err);
  },

  newPasswordRequired: function(userAttributes, requiredAttributes) {
    // User was signed up by an admin and must provide new 
    // password and required attributes, if any, to complete 
    // authentication.

    // the api doesn't accept this field back
    delete userAttributes.email_verified;

    var newPassword = prompt('Enter new password ', '');
    // Get these details and call 
    cognitoUser.completeNewPasswordChallenge(newPassword, userAttributes, this);
  },
});

登录部分开始工作并非易事,但现在它工作正常:在控制台中,我看到:

You are now logged in.
Successfully logged!
accessKeyId: ASIAIRV4HOMOH6DXFTWA

然后,在连接时,出现以下错误:

connect failed: {invocationContext: undefined, errorCode: 8, errorMessage: "AMQJS0008I Socket closed."}

我假设这是因为实际应用于经过身份验证的用户的 Angular 色不允许操作 iot:Connect;我相信是这样,因为我可以为未经身份验证的用户重现完全相同的错误,如果我在未经身份验证的用户的策略中添加以下内容:

{
    "Action": [
        "iot:Connect"
    ],
    "Resource": "*",
    "Effect": "Deny"
},

未经身份验证的用户在尝试连接时将收到相同的错误 AMQJS0008I Socket closed

因此,看起来我针对经过身份验证的用户的策略实际上并未应用于经过身份验证的用户。

在写这个问题之前我做了很多实验。目前,在我的身份池设置中,在“经过身份验证的 Angular 色选择”中,我只有“使用默认 Angular 色”,这确实应该选择我经过身份验证的 Angular 色,即:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "*",
            "Resource": "*"
        }
    ]
}

但我也尝试选择“使用规则选择 Angular 色”并编写一个规则,该规则将根据一些匹配的子句设置我的 Angular 色。

我还尝试在我的用户池中创建一个组,在那里使用相同的 Angular 色,将我的用户添加到该组,并在身份池设置中设置“从 token 中选择 Angular 色”。

没有任何帮助。对于经过身份验证的用户,我不断收到此 errorMessage: "AMQJS0008I Socket closed." 消息,而对于未经身份验证的用户,一切正常,即使策略相同也是如此。

感谢任何帮助。

最佳答案

问题是,对于经过身份验证的 Cognito 用户,将 IAM 策略附加到身份池是不够的:除此之外,还必须为每个身份附加一个IoT 策略(不是 IAM 策略) (基本上,对每个用户),像这样:

$ aws iot attach-principal-policy \
    --policy-name Some-Policy \
    --principal us-east-1:0390875e-98ef-420d-a52d-f4188ce3cf06

同时检查这个线程 https://forums.aws.amazon.com/thread.jspa?messageID=726121

关于javascript - 通过 Cognito Identity Pool 验证的用户的 MQTT 连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42516077/

相关文章:

javascript - 如何从日期范围选择器中选择旧日期?

python-3.x - 如何使用 boto3 在 2 个不同帐户的 S3 存储桶之间复制文件

protocols - 如何在MQTT中实现一对一通信?

java - 如何识别接收消息的MQTT主题?

amazon-web-services - 获取错误配置选项 :\377\376h

mqtt - 将 MQTT 与多个订阅者一起使用

javascript - JS 自动完成的问题。不触发

javascript - 在 JavaScript 中将值插入数组数组

c# - 用于从动态创建的文本框(用 Javascript)捕获数据的 ASP.NET 代码可能是什么样的?

amazon-web-services - AWS Cognito NotAuthorizedException 客户端尝试写入未经授权的属性