写点什么

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

  • 2019 年 9 月 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 年 9 月 20 日 09:08579
用户头像

发布了 1470 篇内容, 共 51.4 次阅读, 收获喜欢 57 次。

关注

评论

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

论层次架构风格

lazytortoise

`MD`语法技巧Typora

sec01张云龙

11月日更 MD MD写法

架构实战营模块七作业

Geek_d18264

架构实战营

Node.js 17 新特征简介

devpoint

node.js Promise 11月日更

数据库审计是什么意思?作用是什么?

行云管家

数据库 安全 IT运维 数据库审计

“智慧粮仓”守卫中国饭碗

森友小锘

大前端 物联网 可视化

超全整理:程序员都在用什么工具?

华为云开发者社区

程序员 技术 设计 编程语言 开发工具

《个保法》施行 | App 隐私合规检测双十一尝鲜仅需99元

蚂蚁集团移动开发平台 mPaaS

隐私保护 移动开发 监管合规

快手微服务架构技术交流会

快手中学

微服务 云原生 稳定性

【等保小知识】等保与分保的三大区别汇总分析

行云管家

网络安全 数据安全 等保 分保

RabbitMQ详解——RabbitMQ架构部署(四)

小翁牌坦克

RabbitMQ Mirror Queue Federation

linux 设置VPN

糖米唐爹

Linux vpn

托管页前端异常监控与治理实战

百度Geek说

大前端

2022第十五届北京国际智慧城市、物联网、大数据博览会

InfoQ_caf7dbb9aa8a

《黑客之道》kali Linux之NMAP高级使用技巧和漏洞扫描发现

学神来啦

Linux 渗透 kali nmap

RabbitMQ详解——服务端存储机制(二)

小翁牌坦克

RabbitMQ mnesia ETS

初入云计算行业,可以考取哪些云计算证书?

行云管家

云计算 腾讯云 阿里云 证书 IT运维

华为云天筹AI求解器:智能世界是道迷人的数学题

脑极体

腾讯安全姬生利:云原生环境下的“密码即服务”

腾讯安全云鼎实验室

云原生 加密

GitHub点击量破百万访问,不愧是被称阿里神作的JDK源码笔记

Sakura

Java 源码 架构 jdk 面试

推荐学Java——初识数据库

逆锋起笔

Java MySQL 数据库 Java后端

何时适合进行自动化测试?(下)

禅道项目管理

自动化测试

能让你从P6+学到P9也只有马士兵老师了,全套学习资源分享

Java架构追梦

Java 编程 架构 面试 马士兵

Vue进阶(幺陆肆):自定义指令之拖拽指令

No Silver Bullet

Vue 11月日更

没有性能瓶颈的无限级菜单树应该这样设计

Tom弹架构

Java 架构 设计模式

学长带路学吉他,这几招足够了

懒得勤快

看企业如何玩转低代码,引发效率革命

云原生开发者社区

云原生 低代码 开发 直播 双十一

华为云·核心伙伴开发者训练营——产业云专场在东莞松山湖圆满落幕

华为云开发者社区

华为云 鲁班会

iOS开发-百度一面总结

iOSer

ios 面试 iOS面试 ios开发 百度面试

网课录屏用什么软件好?Camtasia极简操作,课程重点一目了然

淋雨

Camtaisa

恒源云(GPUSHARE)_CAN: 借助数据分布提升分类性能

恒源云

深度学习

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