免费下载!由 O’Reilly 出版的《NGINX 完全指南》中文版已正式上线 了解详情
写点什么

Cognito Identity Pool + IoT Core 实现 Mobile 端用户对设备权限的精细化控制

  • 2019-09-20
  • 本文字数:6153 字

    阅读完需:约 20 分钟

Cognito Identity Pool + IoT Core 实现 Mobile 端用户对设备权限的精细化控制

场景概述

目前,越来越多的 Iot 厂商会开发自己的 APP,使得终端用户可以通过 APP 绑定自己的设备,检测自己设备的实时情况,并且对设备做即时的控制。在此场景下,Mobile 端的终端用户应该只能发布消息到自己的设备。用户和设备的关系可能是一对多或者多对多,比如同一个 user 拥有多个设备,用户 A 只能发布消息到/userA/deviceX 的 topic 中;多个设备可能受同时受多人控制,此时用户 B 和 C 都有权限发布消息到/device2/temp 下。本文考虑到此两种场景并做展开,利用 Cognito 和 AWS Iot Core,实现终端对设备的精细化控制权限管理。

架构图


通过 cognito user pool,无需自己 coding,即可轻松实现用户的注册、登录、注销等基本操作。Cognito Identity Pool 可以与 cognito user pool 或是其他第三方账号(如 google,facebook)做对接,利用 IAM Role 实现对 AWS 资源的精细化控制。本文同时使用 cognito User Pool 和 cognito identity Pool,实现对 Iot Core 的访问管理。终端用户通过 cognito user pool 的用户池,获得登录 token,通过此登录成功的 token,拿到 cognito Identity Pool Authorized Role 的身份,使得他有权访问 Iot Core 并且只能发布消息到自己的设备控制 topic。用户的登录 ID 和设备之间的绑定关系存储在 AWS NoSQL 数据库 DynamoDB 当中,用户只能发布消息到自己的 Iot 设备。

先决条件

  1. 拥有 AWS 账号

  2. 安装 AWS Iot JavaScript SDK

  3. 安装 Browserify 将 AWS IoT JavaScript SDK(Nodejs 版本)转化为浏览器可以直接引用的 JavaScript 包.

操作步骤

第一步:资源配置

0. 创建 dynamoDB table

创建名称为 iot 的 table,将 IdentityId 为主键,其他的保留默认值即可. 此 table 主要用来维护用户 id 和设备 id 之间的 mapping 关系。


1.创建 cognito 用户池 user pool

输入 user pool 名称(如 cognito-user-pool-for-iot),review defaults, 并根据需求做自定义修改(如可以修改 necessary attributes,密码长度等),此 demo 均利用默认值。

2.创建并配置应用客户端 app client

选择应用客户端,取消 generate client secret 的选项



在左侧 APP-Integration 项目下,需要我们修改的有 2 个地方,一是 APP client setting,修改 callback URL 以及 scope token 作用范围,二是自定义 domain name(需要全 region 唯一)



注意:localhost:8000 仅在测试环境中使用。实际生产环境,这里的 callback 请修改为 https 的网址,注意:不支持 http 协议。请勿写入 http://ip 等形式。


记下 userPoolID 和 app Client ID,在下一步骤中会用到。

3. 创建 cognito identity pool

命名完毕后,对于 authentication provider, 选择 Cognito. 输入上一步记下的两个 ID:user pool ID(User Pools → demo-pool → General Settings → Pool ID)以及 app client ID(User Pools → demo-pool → App Integration → App client settings → demo-app-client→ ID), 同时我们可以勾选允许 unauth 用户访问。


4. 设置 cognito identity pool 权限:授予 Iot 和 DDB 的访问权限

在点击创建后,进入到权限设置页面。可以在这里直接设置,也可以后续在 IAM role 当中随时更新 policy。


Identity pool 会自动创建两个 role,一种为 unauthorized,即未登录仅游客身份的用户,可自行为此类用户授予一些基本的浏览权限;另外一种为 authorized,成功验证身份的用户。


在本文当中,我们主要实现的功能为登录用户可以并且只能访问到隶属于自己的设备,未登录用户仅能网页浏览并且有登录选项。 因此,对于授权用户我们赋予对用户自己的 id 下的设备有着“iot:Connect”, “iot:Publish”, “iot:Subscribe”, “iot:Receive”, “iot:GetThingShadow”的允许权限,以及访问 dynamoDB,和修改 dynamoDB 的权限。${cognito-identity.amazonaws.com:sub}为从 cognito-user-pool 传递过来的变量,标记用户的 identityID。每个 user 不同且唯一。我们通过此值来限定不同 user 之间的访问权限。


  • 对于 authorized users. 请下载 IAM policy 并且替换以下参数:

  • 请将替换为自己的 12 位 ID(去掉<>两个尖括号)

  • 请将去掉尖括号替换为自己使用的区域(去掉<>两个尖括号),如日本为 ap-northeast-1,virginia 为 us-east-1,如使用其他 region,请务必替换为自己的对应代码,其他 region-code 请参考此页. 本文使用日本区域 ap-northeast-1 做演示。 resource 完整示例为 arn:aws:iot:us-west-1:123456789102:client/${cognito-identity.amazonaws.com:sub}。

  • Unauth-Role 的 policy 如下



{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "mobileanalytics:PutEvents", "cognito-sync:*" ], "Resource": [ "*" ] } ]}
复制代码

5.在 Iot 中添加 Iot policy:为 Iot 授予访问权限

在 Iot core 当中安全–策略(policy)页面,添加策略,命名 cognito-identity-general-policy,具体权限如下。Cognito 将通过 attachPolicy 命令为自己授予这条 policy,使得每个 Auth user 有权限访问 Iot 且仅能发消息给自己的设备。此段 policy 也可以在这里找到



{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "iot:Connect", "Resource": "arn:aws:iot:<your-region-code>:<account-id>:client/${cognito-identity.amazonaws.com:sub}" }, { "Effect": "Allow", "Action": "iot:Publish", "Resource": "arn:aws:iot:<your-region-code>:<account-id>:topic/${cognito-identity.amazonaws.com:sub}/*" }, { "Effect": "Allow", "Action": "iot:Subscribe", "Resource": "arn:aws:iot:<your-region-code>:<account-id>:topic/${cognito-identity.amazonaws.com:sub}/*" } ]}
复制代码


至此,通过 cognito 连接 Iot 并只能访问自己资源已经配置完毕,可以用自己的 web 页面嵌入此功能做验证或者测试。 本文用一个 demo 前端界面演示效果。

第二步:前端 demo 代码

此网页实现三个功能,一是登录,注册,是由 cognito user pool 来实现的;


二是设备绑定,此网页模拟了用户拿到设备之后,手输设备号完成绑定的过程,在实际 APP 当中,这一步通常是由扫二维码的形式来实现绑定的,因 web 网页版不好模拟扫码,故用手输的方式;


三是消息收发。点击已有设备,即模拟一次消息传输的过程。页面还有一个 button 是验证发送到其他 topic 会出现什么情况。


完整代码请点击这里<<<<<下载。


  1. (可选步骤,已经附此最终文件 bundle.js)JS 引入 AWSIotDeviceSdk 浏览器版本

  2. (1)安装 AWSIotDeviceSdk Nodejs



#AWSIotDeviceSdk.jsvar AwsIot = require('aws-iot-device-sdk');window.AwsIot = AwsIot; // make it global

复制代码


(2)在 Shell 当中运行 browserify,将 nodejs 转化为前端可引入的 JS


terminal> browserify path/to/AWSIotDeviceSdk.js -o bundle.js
复制代码


  1. 修改前端代码, 替换参数

  2. 在 index.html 中修改以下内容:


(1) 在 function initCognitoSDK() 中替换所有的,,,为自己的值,这一步是设置 cognito 的过程。


AWS.config.region =’’; //替换为自己的 region-code



var authData = { ClientId:'<your-app-client-id>', // APP client id here, 如5smxxxc7lcetqvao6ed967sq01 AppWebDomain : '<your-custom-domain>', // 去掉 "https://" 部分. 样例格式:xxx.auth.ap-northeast-1.amazoncognito.com TokenScopesArray : ['openid','email'], // like ['openid','email','phone']... RedirectUriSignIn : 'http://localhost:8000/', //只供本地测试,实际生产请写https网址,且必须要和前面控制台中cognito callback设置保持一致,不然会报redirect_mismatch的错误 RedirectUriSignOut : 'http://localhost:8000/', //只供本地测试,实际生产请写https网址,且必须要和前面控制台中cognito callback设置保持一致,不然会报redirect_mismatch的错误 IdentityProvider : '<identity-provider-id>', //替换为自己的identity pool id UserPoolId : '<your-user-pool-id>', //user pool ID,example: ap-northeast-1_410bH7K8x AdvancedSecurityDataCollectionFlag : false };
//在onsuccess回调函数当中 AWS.config.credentials = new AWS.CognitoIdentityCredentials({ IdentityPoolId: '<identity-provider-id>',//identity provider id,example: ap-northeast-1: xxxxxxxx-xxxx-xxxx-xxxxxx Logins: login });
复制代码


user pool ID 在 User Pools → demo-pool → General Settings → Pool ID


app client ID 在 User Pools → demo-pool → App Integration → App client settings → demo-app-client→ ID 可找到


(2)如果 iot policy 为自己命名的,则 attachPolicy(“cognito-identity-general-policy”, principal)第一个参数替换为自己的 iot policy name。通过此操作,当前用户在拿到 token 后,可以实现与 iot core 的互通。


(3)在 function connect(principal)当中替换


  device = AwsIot.device({      clientId: clientID,      host: '<your-iot-endpoint>',   //example: xxxxxx.iot.<your-region-code>f.amazonaws.com      protocol: 'wss',      accessKeyId: AWS.config.credentials.accessKeyId,         secretKey: AWS.config.credentials.secretAccessKey,      sessionToken: AWS.config.credentials.sessionToken    });
复制代码


此 iot-endpoint 可以在 iot core-setting 当中找到:



(4)在 function userButton(auth)当中替换自己的,,,,实现页面跳转。


  function userButton(auth) {    var state = document.getElementById('signInButton').innerHTML;    if (state === "Sign Out") {
//*************************需自行修改,替换为自己的域名,clientid以及回调地址************************// document.getElementById("signInButton").href="https://<your-custom-domain>.auth.<your-region-code>.amazoncognito.com/logout?response_type=code&client_id=<your-client-id>&logout_uri=<your-call-back-url>"; document.getElementById("signInButton").innerHTML = "Sign In"; auth.signOut(); showSignedOut();
} else { //auth.getSession(); //*************************需自行修改,替换为自己的域名,clientid以及回调地址************************// document.getElementById("signInButton").href="https://<your-custom-domain>.auth.<your-region-endpoint>.amazoncognito.com/login?response_type=code&client_id=<your-client-id>&redirect_uri=your-call-back-url>"; } }
复制代码


(5)在 function publishMessage(env)当中,可以选择是否设置 qos 参数。这两种参数会在后续的实验中有不同的效果,我们先不设置 qos 试试看(默认)。


  1. 搭建测试服务器

  2. 有两种方式:


(1) localhost 方式 在 shell 当中运行


python -m SimpleHTTPServer
复制代码


在浏览器当中输入http://0.0.0.0:8000 或者 localhost:8000 进行验证。建议打开浏览器的 developer tools 查看日志以及 MQTT 传输过程。


注意:这种场景下,在点击 sign in 之后,因浏览器安全等级不同,有些浏览器可能会显示 connecting… unable to connect websocket 的 error 提示,这是因为页面停留在原 http 页面,无法自动进行证书验证,此时需要在浏览器新 tab 当中手动输入 https://xxx(复制原本 wss://xxxx 后面的 url)进行手动的加载证书的操作。之后再刷新原 localhost:8000 即可正常加载。


(2) 在实际生产当中,请直接打开 https://your-own-domain 进行测试。 留意:如果用自己的域名,请务必保持 cognito–APPclientSetting 中以及代码里面所有的 callback 回调地址也都改为 your own domain,否则会报 redirect_dismatch 的错误

验证说明

(1)新建的 cognito user pool 是没有用户的,可以在页面验证用户注册和用户登录的过程,或者直接在 cognito user pool 当中手动创建新用户也可以。



(2)原始 dynamoDB 当中没有数据,可以通过点击 add a new device 的按钮来模拟设备绑定的过程。这时可以输入一串字符(如 iphone-15341),点击 submit 按钮,等待几秒钟,在页面最下方即出现设备列表 iphone-15341 publish。



这时 dynamodb 写入一条新数据,代表新增一条 identityID 与 device 之间的绑定关系的记录。当用户下一次登录时,会直接展示这些 device lists。


这个表的结构如图所示:



(3)进入 Iot-test 页面,订阅 #(通配符,即订阅所有 topic)。在 web 页面点击刚刚出现的 xxxx publish 的按钮,可以在 console 当中看到实时的消息推送,此时 Iot 连接并且发布消息已成功。前端页面会显示发送出去的 message 的 topic 和具体内容。



(4)web 页面的”Demo Unauthed situation“这个按钮,是模拟当前用户如果要发送不在权限范围内的情形,这个按钮会发送到名为 test 的 topic。这时候我们点击此 button,会出现两种不同的情况:


  • 如果在 publishMessage 当中,不设置 Qos(默认代码),这时候 MQTT 不会验证传输是否成功,尽管 web 页面会显示发送成功,然而在 Iot 的 console 当中,会发现这条消息实际是未送达且永远不会被送达的。

  • 如果设置{qos:1}(代码改动如下)


function publishMessage(env) {   var topic = env.target.topic;   var msg = env.target.msg;   //device.publish(topic,msg, function (err) {   device.publish(topic,msg, { qos: 1 }, function (err) {         if (err) {             console.log("failed to publish iot message! ",topic);             console.error(err);         } else {             console.log("published to TopicName: ", topic);             openTab("messagedetails");             showMessage("Message Published", "Topic: "+topic , "Message: "+msg);         }     });
}
复制代码


因权限设置问题,Iot 仍然无法收到这条消息,但是 web 页面会不断重连尝试重新发送,根据官方解释,Iot 会尝试长达一个小时的重传,此时在点击 demo unauthed situation 的按钮后,页面会出现卡顿,打开 developer tool 会发现不停的 reconnect 尝试重传。此时点击其他 publish 的 button 也没有反应。


注:实际生产中,因为不会有这样一个 unauth test 的 button,因此可以设置 qos:1。 引用文档:”AWS IoT will retry delivery of unacknowledged quality-of-service 1 (QoS 1) publish requests to a client for up to one hour. If AWS IoT does not receive a PUBACK message from the client after one hour, it will drop the publish requests.”


参考链接:


https://aws.amazon.com/cn/blogs/iot/configuring-cognito-user-pools-to-communicate-with-aws-iot-core/


作者介绍:


李天歌


AWS 解决方案架构师


许昌月


AWS 解决方案架构师


本文转载自博客 aws。


原文链接:


https://amazonaws-china.com/cn/blogs/china/cognito-identity-pool-iot-core-realize-mobile-user-control/


2019-09-20 09:08735
用户头像

发布了 1606 篇内容, 共 71.6 次阅读, 收获喜欢 68 次。

关注

评论

发布
暂无评论
发现更多内容

设计微博系统中”微博评论“的高性能高可用计算架构

WYT

架构实战营

总结

杰语

阿里“宝妈级”之作,这份Spring Security应用到源码手册,全是精华

Java spring 程序员 架构 计算机

FastApi-13-文件上传-1

Python研究所

FastApi 8月日更

架构实战营 | 毕业设计

架构实战营

从0开始的TypeScriptの八:类

空城机

JavaScript typescript 大前端 8月日更

智能边缘开源框架Baetyl,构建边缘融合智能应用

百度开发者中心

AI 最佳实践 物联网 边缘计算 开源技术

Android SDK 版本属性

Changing Lin

8月日更

蚂蚁金服+拼多多+抖音+天猫Java面经合集,金九银十Java开发校招社招福音!

编程菌

Java 编程 程序员 面试 计算机

财富自由的本质及如何实现财富自由?

非著名程序员

认知提升 个人提升 财富自由 8月日更

架构实战营 毕业总结

Ahu

拆分电商系统为微服务

thewangzl

老外为了在MacBook上玩原神,让M1支持了所有iOS应用 | Github每周精彩分享第一期

Zhendong

GitHub

秒杀架构设计

鲲哥

前端之算法(五)顺序和二分搜索

Augus

数据结构与算法 8月日更

【LeetCode】 礼物的最大价值Java题解

Albert

算法 LeetCode 8月日更

序列化单例模式的实现————readResolve 源码解读

4ye

Java 源码 后端 序列化 8月日更

浏览器数据库 IndexedDB(一) 概述

编程三昧

数据库 大前端 indexedDB 8月日更

架构实战营 模块五作业

孫影

架构实战营 #架构实战营

网络攻防学习笔记 Day106

穿过生命散发芬芳

网络安全 8月日更

让我们一起开发【菜谱系统】吧,滚雪球学 Python 第三轮项目计划

梦想橡皮擦

8月日更

Flink CDC我吃定了耶稣也留不住他!| Flink CDC线上问题小盘点

王知无

fil币价格行情怎么样?fil币价值和未来在哪?

fil币价格行情怎么样 fil币价值和未来在哪

python爬取下载m3u8加密视频,原来这么简单!

Python研究者

8月日更

设计千万级学生管理系统的考试试卷存储方案

架构0期-Bingo

架构实战营 模块三

听闻

极客大学架构实战0期毕业总结

谢博琛

如何在二三线城市月薪过万(三)java偏功能实现的面试题,有备无患!!

小鲍侃java

8月日更

抵制不良饭圈文化,互联网平台应该肩负哪些责任

石头IT视角

【Vue2.x 源码学习】第三十六篇 - 组件部分 - Vue.extend 实现

Brave

源码 vue2 8月日更

架构训练营毕业总结

Geek_e0c25c

架构实战营

Cognito Identity Pool + IoT Core 实现 Mobile 端用户对设备权限的精细化控制_文化 & 方法_亚马逊云科技 (Amazon Web Services)_InfoQ精选文章