如何使用AWS IoT向/从Web浏览器发送/接收消息

37
我们正在尝试使用亚马逊云服务物联网(AWS IoT)在Web浏览器之间发送/接收消息(例如:)。由于AWS IoT支持JavaScript,我们希望这是可能的...
我们在AWS IoT文档中搜索,但只找到了服务器端示例(其中公开了AWS secrets/keys...)
是否有任何关于如何在浏览器中使用WebSockets/MQTT通过AWS IoT发送/接收消息的好的可行示例或教程(例如:使用AWS Cognito进行身份验证)?谢谢!
4个回答

27

这里是一个使用JS中的Cognito身份池进行连接、发布和订阅响应的示例。

// Configure Cognito identity pool
AWS.config.region = 'us-east-1';
var credentials = new AWS.CognitoIdentityCredentials({
    IdentityPoolId: 'us-east-1:your identity pool guid',
});

// Getting AWS creds from Cognito is async, so we need to drive the rest of the mqtt client initialization in a callback
credentials.get(function(err) {
    if(err) {
        console.log(err);
        return;
    }
    var requestUrl = SigV4Utils.getSignedUrl('wss', 'data.iot.us-east-1.amazonaws.com', '/mqtt',
        'iotdevicegateway', 'us-east-1',
        credentials.accessKeyId, credentials.secretAccessKey, credentials.sessionToken);
    initClient(requestUrl);
});

function init() {
  // do setup stuff
}

// Connect the client, subscribe to the drawing topic, and publish a "hey I connected" message
function initClient(requestUrl) {
    var clientId = String(Math.random()).replace('.', '');
    var client = new Paho.MQTT.Client(requestUrl, clientId);
    var connectOptions = {
        onSuccess: function () {
            console.log('connected');

            // subscribe to the drawing
            client.subscribe("your/mqtt/topic");

            // publish a lifecycle event
            message = new Paho.MQTT.Message('{"id":"' + credentials.identityId + '"}');
            message.destinationName = 'your/mqtt/topic';
            console.log(message);
            client.send(message);
        },
        useSSL: true,
        timeout: 3,
        mqttVersion: 4,
        onFailure: function () {
            console.error('connect failed');
        }
    };
    client.connect(connectOptions);

    client.onMessageArrived = function (message) {

        try {
            console.log("msg arrived: " +  message.payloadString);
        } catch (e) {
            console.log("error! " + e);
        }

    };
}

此处credentials.get调用的文档。

记得为您的 IAM 角色授权以进行订阅/发布。这里是一个示例:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "iot:Connect"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "iot:Receive",
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "iot:Subscribe",
            "Resource": [
                "arn:aws:iot:us-east-1::your/mqtt/topic"
            ]
        },
        {
            "Effect": "Allow",
            "Action": "iot:Publish",
            "Resource": [
                "arn:aws:iot:us-east-1::your/mqtt/topic"
            ]
        }
    ]
}

7
参考sigv4函数可在此处找到:http://draw.kyleroche.com/sigv4utils.js。 - Kyle Roche
我遇到了以下错误: aws-sdk-2.7.1.js:6834 Uncaught Error: moment is not defined(…)callListeners @ aws-sdk-2.7.1.js:6834emit @ aws-sdk-2.7.1.js:6810emit @ aws-sdk-2.7.1.js:4054transition @ aws-sdk-2.7.1.js:3831runTo @ aws-sdk-.....我已经更新了AWS SDK,但仍然遇到相同的错误。你能帮我解决吗?如果可能的话,请分享一下你正在使用的aws-sdk.js文件。 - Bhavik Joshi
你使用了"iotdevicegateway",作为参数传递的是什么?我们必须传递resourceId还是DeviceId? - Bhavik Joshi
只需将 moment 添加到您的应用程序中:npm i moment --save。同时,“iotdevicegateway” 保持字符串格式。 - Georgii Oleinikov
只是出于好奇,你需要使用类似这个吗?我在代码中看到了new Paho.MQTT.Client,但我不知道它从哪里来。 - Dan Esparza
如果有人正在寻找阴影示例,请使用此链接:https://gist.github.com/ma2shita/905971e4af2a0b9f73add70b75ee9fc3。请按照上面的说明为未经授权的用户授权您的IAM角色。 - Hammad Tariq

2
如果有其他人正在寻找解决方案:这里有一个教程,通过一个简单的聊天应用程序演示了如何使用AWS IOT上的Serverless和Websockets将实时更新传递到ReactJS前端。教程的源代码可以在Github上获取。

3
此示例不包含 Cognito 支持。不清楚的是:该示例是否在 JavaScript 源代码中暴露了密钥? - Dan Esparza

1

在浏览器中集成AWS IoT很难找到好的教程。

基本上,您需要有一些身份验证方法(Facebook、Google、AWS Cognito、具有SAML支持的自己的SSO服务),然后您需要执行以下步骤:

  1. 使用您的身份验证方法配置Cognito用户池或联合身份池。
  2. 在浏览器中,您必须实现扩展流程(https://aws.amazon.com/blogs/mobile/understanding-amazon-cognito-authentication-part-4-enhanced-flow/
  3. 您需要为用户的Cognito identityId在IoT中AttachPolicy - 它将被用作主体(与设备使用证书的方式相同)。
  4. 您需要使用https://github.com/aws/aws-iot-device-sdk-js创建MQTT客户端,并提供从扩展流身份验证中接收到的临时accessKeyIdsecretKeysessionToken

1
非常重要的是要理解这里IAM策略和AWS IOT策略之间的区别。假设您使用cognito用户池作为身份提供者。
首先,您需要设置一个cognito身份池,将身份池链接到您的用户池并为此身份池分配角色(将IAM策略附加到此角色)。
其次,在您的应用程序中,您首先登录以获取用户池凭证,然后调用
    AWS.config.credentials = new AWS.CognitoIdentityCredentials({
      IdentityPoolId: 'us-west-2:b8d2b32b-cbab-4ae3-9d47-1624d09c9350',
      Logins: {
        'cognito-idp.us-west-2.amazonaws.com/${userPoolIdentity}': userPoolCredential.getIdToken().getJwtToken(),
      }
    });

用AWS临时访问凭证交换您的用户池凭证:

    AWS.config.getCredentials(e => {
      if(e) console.log("Get credential failed", e);
      this.device = AwsIot.device({//AwsIot is the aws-iot-sdk package
        clientId: clientID,//clientId is just random string
        host: '*-ats.iot.us-west-2.amazonaws.com',//replace * with your own host
        protocol: 'wss',
        accessKeyId: AWS.config.credentials.accessKeyId,
        secretKey: AWS.config.credentials.secretAccessKey,
        sessionToken: AWS.config.credentials.sessionToken
      });
      this.device.on('connect', function() {
        console.log("DEVICE CONNECTED");
      });
      this.device.subscribe('test');
      this.device
      .on('message', function(topic, payload) {
        console.log(`TOPIC IS ${topic}\nMESSAGE IS ${payload.toString()}`);
      });
    });

但是上面的代码不起作用!!!这里有个棘手的问题:通过交换您的用户池凭据获得的凭据仅是代表您刚刚附加到身份池的AWS IAM策略的临时凭据!当请求连接您的IOT时,AWS将检查是否允许请求以及是否允许执行用户请求。您已经获得了IAM策略,因此可以请求,但它将检查附加到此标识的AWS IOT策略。由于您还没有这样做,因此不允许您执行您真正请求的操作(即连接)。因此,在第一次要连接时,您应该向此标识附加一个IOT策略。您可以通过命令行或
  (<AWS.CognitoIdentityCredentials>AWS.config.credentials).refresh(e => {
    if(e) console.log('error', e);
    const principal = (<AWS.CognitoIdentityCredentials>AWS.config.credentials).identityId;
    console.log(`IdentityId: ${principal}`);
    this.attachPrincipalPolicy("test-delete-after-use", principal);
  });
  attachPrincipalPolicy(policyName, principal) {
    new AWS.Iot().attachPrincipalPolicy({ 
      policyName: policyName, // you need to create policy beforehand in iot
      principal: principal 
    }, err => {
      err ? console.log('ATTACH PRINCIPAL POLICY ERROR', err) : console.log('ATTACH PRINCIPAL POLICY SUCCESS');
    });
  }

现在,当身份尝试连接IOT时,IOT会找到与此身份相关联的策略,并批准此连接。
抱歉措辞不佳。简而言之,您需要澄清策略和策略之间的区别。这只是我的理解,可能有错误的地方。如果您发现了,请留下评论或编辑我的答案。
重要提示 刚刚从官方文档中找到了这两个策略之间的关系:https://docs.aws.amazon.com/iot/latest/developerguide/pub-sub-policy.html请查看“HTTP和WebSocket客户端的策略”部分。

我真的很想看看你对这个问题的完整解决方案,如果可能的话!这正是我目前面临的问题。 - Ashkan Hovold
@AshkanHovold,最近怎么样了?你解决那个问题了吗?我也遇到了同样的情况,但是我发现 AWS 的文档很难理解,所以正在寻找更多信息... - José Pulido

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接