咱們想象這麼一個IoT應用場景:廠商A使用AWS IoT來開發物聯網解決方案,那麼A把設備賣給用戶的時候,須要使用戶可以登入AWS IoT系統來控制其購買的A的設備,也就是說給用戶分配適當的權限。下面本文簡要歸納討論如何實現這樣一個場景。javascript
部分細節能夠參考這個博客:https://blog.csdn.net/luo_bo1/article/details/84567988html
1. 用戶身份的管理java
首先,用戶必須有一個獨特的身份在這個系統中。事實上,開發者甚至不須要本身維護一個管理身份的服務器,用戶也不肯意註冊那麼多帳號。爲解決這個問題,便產生了直接使用第三方帳號身份來映射到AWS IoT系統中的方法,也就是說,用戶只要有一些公共的第三方身份提供商的帳號(如谷歌、亞馬遜等),便容許直接使用AWS IoT系統。本文使用了Login with Amazon這個第三方服務,廠商只要根據Login with Amazon的文檔實現一個接口便可。主要有以下幾步:web
(1) 在developer.amazon.com後臺註冊一個OAuth的客戶端,還要提供隱私策略,得到一個亞馬遜發放的OAuth ClietID和Client Secret,這樣亞馬遜才能認證這是哪一個開發者想得到用戶的信息。在用戶受權後,便可向亞馬遜得到用戶的基自己份信息。api
(2)本人是用Web實現的,所以須要設置OAuth過程當中須要的回調URL,而且把這個URL加入Login with Amazon的白名單。此外,還要在Web setting中設置Allow origin。在調用亞馬遜這個接口時,亞馬遜會驗證ClientId,web URL來認證開發者的身份,而且有了origin也能防止這是別人在冒用你的ClientID(用戶點擊login with amazon的時候瀏覽器會攜帶origin發給亞馬遜,儘管這個有時能夠僞造);用戶受權後,結果token會以重定向的方式讓用戶瀏覽器訪問白名單中存在的回調URL,這樣就確保只有開發者的服務器能夠得到token,防止別人偷取。瀏覽器
(3)開發者得到了用戶的token,就能夠查詢得到用戶在Amazon的 信息,進而得到到一個惟一的用戶ID。這個ID應該是惟一匿名化的身份標識,即不會泄露用戶的信息,不一樣Client得到的也不同,防止用戶被追蹤。安全
2. 給對應用戶分配適當的權限服務器
如今咱們得到了用戶的身份,可是用戶要訪問的是AWS IoT中的資源,如何設置才能將AWS中的權限,關聯至第三方身份提供商給的身份呢?這就須要AWS Cognito的Identity Pool出馬了。websocket
(1)首先,cognito須要驗證用戶的身份,而後在Identity Pool中建立一個對應的身份映射。這首先須要在cognito的Identity Pool中設置Authentication providers,添加開發者建立的login with amazon的標識,即session
(2)開發者得到用戶第三方token後,向cognito發送該token,就代表了該用戶身份,cognito會再返回給程序一系列cognito的token。因爲用戶cognito就是AWS本身的服務,因此能夠關聯AWS IoT中的權限給該用戶使用。具體動態關聯的方法沒有深究,只是用aws cli簡單測試實現,正確動態作法能夠參考官方PPT:https://www.slideshare.net/AmazonWebServices/iot-apps-with-aws-iot-and-websockets
aws cli使用須要先設置, 能夠參考https://razeencheng.com/post/tool-awscli-overview-1
指令有點坑,記錄一下:
aws iot attach-policy --policy-name <value> --target <value>
(3)最後強調一點,策略設置時要注意權限的控制,AWS提供了策略變量來得到用戶特有的不變憑證,參考https://blog.csdn.net/luo_bo1/article/details/84567988便可。另外設置的時候有點坑,既要設置認證過cognito用戶的粗粒度權限,又要在AWS IoT中設置細粒度的權限而且關聯到cognito用戶上。
3.附錄JS代碼
注:必須本身搭建個web服務器來測試,不然因爲瀏覽器安全限制(好像是專門本地的文件)沒法使用亞馬遜的js API。推薦XAMPP,起名成html直接放到htdoc下就行了,xampp還直接支持https。
1 <!doctype html> 2 <html lang="en_US"> 3 4 <head> 5 <script src="https://sdk.amazonaws.com/js/aws-sdk-2.451.0.min.js"></script> 6 </head> 7 8 <body> 9 <a href id="LoginWithAmazon"> 10 <img border="0" alt="Login with Amazon" 11 src="https://images-na.ssl-images-amazon.com/images/G/01/lwa/btnLWA_gold_156x32.png" width="156" 12 height="32" /> 13 </a> 14 <button onclick="myFunction()">Myfunction</button> 15 16 <div id="amazon-root"></div> 17 <script type="text/javascript"> 18 19 window.onAmazonLoginReady = function () { 20 amazon.Login.setClientId('amzn1.application-oa2-client.XXXXX'); 21 }; 22 (function (d) { 23 var a = d.createElement('script'); a.type = 'text/javascript'; 24 a.async = true; a.id = 'amazon-login-sdk'; 25 a.src = 'https://assets.loginwithamazon.com/sdk/na/login1.js'; 26 d.getElementById('amazon-root').appendChild(a); 27 })(document); 28 </script> 29 30 <script type="text/javascript"> 31 document.getElementById('LoginWithAmazon').onclick = function () { 32 options = { scope: 'profile' }; 33 amazon.Login.authorize(options, 34 'https://127.0.0.1/test.html'); 35 return false; 36 }; 37 </script> 38 39 <script> 40 function myFunction() { 41 // Set the region where your identity pool exists (us-east-1, eu-west-1) 42 AWS.config.region = 'us-east-1'; 43 44 // Configure the credentials provider to use your identity pool 45 AWS.config.credentials = new AWS.CognitoIdentityCredentials({ 46 IdentityPoolId: 'us-east-1:d9fe3941-df89-4190-ab80-XXXXX', 47 Logins: { // optional tokens, used for authenticated login 48 'www.amazon.com': '第三方登錄得到的token' 49 } 50 }); 51 //檢查得到的用戶token是否有效https://api.amazon.com/auth/O2/tokeninfo?access_token=Atza%7CIwEBINapjp9vq3UgptE95f5fqL4DQ5K57Ex5tWTLh0D6K3-omYt8N2H_D-H8tDnn9fyqkrbZ0HdrnQJ4F2_-VtMVB5IOM5quEqr8qZCVVOswPKBHYnL5VwZ4YXtWJiqkssPlsvygcSD74lJWJlAVGTewHP9HWAR4HL4kADPJIyKxI2i_BWpGrDpQb6nw5Yeh6VbtTG9zTWpZUfZsENpkoMo6K5m0H-rw_NmiiZxIBsaOgtIlYTTcG5qKcRFevPXk8SQ8BZKRmXd5Hx2M1bld4rInXLfR41OvuTXH1GKXJHVKMc2hvGt6sMOCcqAXw2ABKAciYAQ1X9uV-RD5zWcp02bw7fgKr8IgwmORyHUhLnnwY8FRYTUQQcTlNHsHVzsbSQ7FYZn7IST9O7nKiSyUryh3VJyCnEqyyvpDzIhSjNjPIyIprpKZoZL1iVKH0oLL_4slT79DVAmuOsUjUKjXnWHbImrF0ZZissrfHPCE2708RWwu-ZgpSsmhPqgRpgE-TlX803ziNo2kvazKpdPg6O6MGG7H2yV8PUW-zwVXO1XxJTK4Nw 52 53 // Make the call to obtain credentials 54 AWS.config.credentials.get(function () { 55 // Credentials will be available when this function is called. 56 var accessKeyId = AWS.config.credentials.accessKeyId; 57 var secretAccessKey = AWS.config.credentials.secretAccessKey; 58 var sessionToken = AWS.config.credentials.sessionToken; 59 var identityId = AWS.config.credentials.identityId; 60 console.log(accessKeyId); 61 console.log(secretAccessKey); 62 console.log(sessionToken); 63 console.log(identityId); 64 65 }); 66 } 67 </script> 68 69 70 </html>