0.前言
前段時間忙了其餘事了,感受利用週末的時間效率好低哦。沒有平時上班時間的效率高。哈哈哈。這篇博客,主要是物聯網業務服務器前期的一些簡單設計。主要是設備如何進行登陸,從業務服務器那裏獲取Token後,登錄到MQTT服務器。業務服務器對設備的登陸驗證,ACL權限驗證這兩方面。主要是把業務服務器與MQTT服務器聯繫起來。javascript
距離上次EMQ學習已經有一段時間了,測試服務器也已經換了。因爲一些緣由,只能用本身的服務器了。博客中出現的IP或者域名,因爲只是測試環境,沒有進行過多的限制,有幸看到博客的,請不要搞破壞哦。哈哈哈。/滑稽html
每一個人對業務的設計的不一樣的,我只是根據本身的瞭解來設計的。有更好的想法,能夠在下面評論區,跟我討論哦。java
1.EMQ服務器配置
本次使用2.3.5版本。直接是從github.com上拉取下來的,而後進行源代碼進行安裝的。前期開發不用涉及到插件開發,能夠直接使用官網提供的二進制包。否則的話,就用源代碼本身編譯。注意這裏若是本身編譯的話,Erlang要 R20+版本才能夠。本身到http://www.erlang.org 下載新版的Erlang/OTP。node
一切的編譯步驟,我在前面的博客有提到,不清楚的能夠看我前面的博客。雖然EMQ進行了小版本更新,可是大致的編譯流程仍是差很少了。這裏就很少說了。jquery
編譯後,會在emq-relx目錄下生成_rel/emqttd目錄。git
我以爲MQTT通訊服務器與業務服務器是要儘可能分開的,特別是不要在MQTT服務器裏作過多的業務處理。因此使用EMQ服務器裏面的賬號驗證和ACL權限驗證。採用的是Redis中間件驗證方式。github
因爲默認的EMQ服務器是很少賬號密碼進行驗證和主題的驗證。這裏咱們要開啓驗證。下面的這些配置是對默認的配置進行的修改。ajax
(1)data/loaded_plugins 文件redis
這裏要增長一行emq_auth_redis算法
(2)etc/emq.conf
因爲如今是單服務器,性能配置什麼都是默認的就能夠。如今我尚未了解全部的配置,性能調優之後看有沒有機會了解。
這裏要修改的是能夠修改node.name 和 node.cookie,兩個也可使用默認就能夠。
因爲默認的EMQ服務器是不檢查賬號密碼和ACL權限的。這裏須要修改emq.conf使其要進行驗證。還有cache_acl這個默認是true, 測試的時候最好是設置爲false,這裏若是是true的話,那麼EMQ一樣會對ACL進行驗證。可是隻驗證一次,就是在第一次發佈或者訂閱對應的Topic時會去判斷ACL,若是經過了,那麼下次對這個Topic進行sub/pub是再也不進行判斷驗證的,同理不經過了,下次也不會進行驗證。若是有cache是能夠提升性能,可是對於那些須要對權限動態修改的業務場景,這個功能就不能用了。對應的配置項是
1 mqtt.allow_anonymous = false 2 mqtt.acl_nomatch = deny 3 mqtt.cache_acl = false
(3)etc/plugins/emq_auth_redis.conf
修改對應的redis地址和密碼, 分別對應的配置項是 auth.redis.server=127.0.0.1:6379 和 auth.redis.password=password 剩下的cmd不用修改,使用默認的,後續開發若是須要自定義的,能夠修改這裏的cmd。
嗯,剩下的就不用再配置了。
./bin/emqttd start 啓動EMQ服務器就能夠。而後經過Web管理界面進行查看,服務是否啓動。而後在裏面提供的WebSocket界面測試鏈接。
2.業務代碼
若是在EMQ服務器裏作業務處理的話,不是不行,可是呢,Erlang這個語言,處理業務很差,我也不熟悉,做爲一個項目來講,招人也很差招。
我仍是使用較爲通用的Java來作業務處理。Java的生態會好不少。本次使用Spring Boot 2.0框架。因爲本篇博客主要講的是物聯網業務方面的,關於Spring Boot的一些配置,這裏就不展開了。之後有機會再寫成博客說明。
從上面的圖能夠看到,如今沒有賬號密碼是不能登陸到MQTT服務器了。EMQ是經過查詢Redis而後進行驗證的。因此我只須要在業務服務器增長一段往Redis服務器寫入權限控制的數據記錄便可。關於默認的格式,參考EMQ文檔。
Login代碼段
1 @Autowired 2 private StringRedisTemplate stringredisTemplate; 3 4 @RequestMapping(value="login") 5 public @ResponseBody IOTDeviceModel login(HttpSession session, 6 @RequestParam("username") String username, @RequestParam("password") String password){ 7 //檢驗賬號密碼 8 IOTDeviceModel dev = new IOTDeviceModel(); 9 if(username.equals("demo")){ 10 dev = getIOTDeviceModelDemo(); 11 }else if(username.equals("test")){ 12 dev = getIOTDeviceModelTest(); 13 }else{ 14 dev.setMsg("用戶名,密碼錯誤."); 15 return dev; 16 } 17 session.setAttribute("session_user", dev); 18 //設置到 mqtt-redis 並返回token 19 stringredisTemplate.opsForHash().put("mqtt_user:" + dev.getUUID(), "password", dev.getToken()); 20 stringredisTemplate.expire("mqtt_user:" + dev.getUUID(), 100, TimeUnit.SECONDS); 21 //這裏查詢模擬數據數據庫,容許當前用戶能夠發佈和訂閱的Topic 22 stringredisTemplate.opsForHash().put("mqtt_acl:" + dev.getUUID(), "/publicroom", "3"); 23 //返回成功 24 dev.setMsg("建立成功, 請使用uuid,token 登錄到mqtt服務器"); 25 return dev; 26 }
GetModel代碼段
1 //測試用戶 Demo 2 private IOTDeviceModel getIOTDeviceModelDemo(){ 3 IOTDeviceModel model = new IOTDeviceModel(); 4 model.setDevid(1); 5 model.setUsername("demo"); 6 model.setPassword("demo"); 7 model.setUUID("5a53a33d-98af-4f87-bb57-cc2e21450b36"); 8 model.setToken(UUID.randomUUID().toString()); //生成臨時的Token 9 return model; 10 } 11 //測試用戶Test 12 private IOTDeviceModel getIOTDeviceModelTest(){ 13 IOTDeviceModel model = new IOTDeviceModel(); 14 model.setDevid(2); 15 model.setUsername("test"); 16 model.setPassword("test"); 17 model.setUUID("f9a06e81-3f12-425b-b58d-21fca17b9932"); 18 model.setToken(UUID.randomUUID().toString()); 19 return model; 20 }
上面的代碼很簡單了,就是判斷當前賬號密碼是否正確,若是正確的,就寫入Redis。可能會有疑問,爲何設置到Redis的密碼,不直接使用password字段,而是隨機生成Token。這是因爲業務中數據庫保存的密碼通常都是加密後的。而加密算法也是各不相同,默認的MD5可能不知足,固然也有基於一些其餘的緣由。這裏就是返回Token,而後用戶、設備經過業務服務器獲取到Token,登陸到MQTT服務器上。
這樣就登陸成功了。如今這個賬號只能發佈和訂閱/publicroom這個主題。經過自帶的測試工具進行測試以下
能夠發現,分別對/World 和 /publicroom這兩個主題進行訂閱和發佈,都是成功的,可是真正在服務器發送數據通訊的只有/publicroom這個主題,由於只有這個主題是被容許的,/World這個主題不容許。
其實按照正常邏輯來講,這裏的/World最好是連訂閱都是不容許的,可是好像默認的這裏WebSocket插件沒有作處理。若是之後我基於本身開發插件的話,這裏能夠進行限制處理了。
3.測試結果
主要從新梳理一下流程。
(1)一個簡答的測試界面
1 <!DOCTYPE html> 2 <html xmlns:th="http://www.thymeleaf.org" 3 xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3"> 4 <head> 5 <meta name="viewport" content="width=device-width,initial-scale=1"/> 6 <meta charset="UTF-8"/> 7 <title>EMQ-測試</title> 8 </head> 9 <body> 10 如下是模擬用戶/設備登陸業務服務獲取Token<br> 11 用戶名: <input id="username" /> 12 密碼: <input id="password" /> 13 <button id="login-btn">登陸業務服務器</button> <br> 14 登錄後信息: <div id='login-ret'></div> 15 16 <hr> 17 如下是用戶/設備獲取Token後登陸到MQTT服務器<br> 18 用戶名: <input id="mqtt-username"/> 19 密碼: <input id="mqtt-password"/> 20 <button id="mqtt-login-btn">登陸MQTT</button> <br> 21 登錄後信息: <div id="mqtt-login-ret"></div> 22 23 <hr> 24 登陸到MQTT後 25 <script src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js" type="text/javascript"></script> 26 <script src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.min.js" type="text/javascript"></script> 27 <script th:inline="javascript"> 28 jQuery(function($){ 29 bindBtnLogin(); 30 }); 31 32 function bindBtnLogin(){ 33 $("#login-btn").bind('click', function(){ 34 var username = $("#username").val(); 35 var password = $("#password").val(); 36 $.post("/login", { 37 username: username, 38 password: password 39 }, function(ret){ 40 console.log(ret); 41 $("#login-ret").html(JSON.stringify(ret)); 42 }); 43 }); 44 } 45 </script> 46 </body> 47 </html>
輸入demo demo 進行登陸,而後返回Token,而後我使用MQTT客戶端去鏈接。這裏的客戶端使用的是 Eclipse Paho MQTT Utility 工具。
填寫對應的服務器地址,而後在選項裏寫入賬號密碼,這裏的賬號就是上圖的UUID,密碼就是上圖的Token了。而後登陸成功。
(2)查看Redis數據
這裏使用Redis客戶端進行查看,方便調試
這裏的mqtt_user:** 因爲設置了TTL,因此會在一段時間後自動刪除掉。
(3)客戶端訂閱主題
依次在下面訂閱/publicroom和/TTT兩個主題,會發現兩個都訂閱成功(具體緣由,上面有說到)。而後在下面的發佈,分別對/publicroom和/TTT主題進行發佈信息。下圖是運行結果。注意這裏的訂閱要分開進行訂閱,不要兩個選中而後訂閱。這裏的/TTT訂閱不成功了?這麼說,EMQ服務器應該是有處理返回的。
(4)再用另外的賬號
這裏同理,按照上面的流程,再用另外的賬號,進行登陸,而後兩個賬號互發信息。經測試,基本符合預期的。
(5)Web管理界面
這裏看一下幾個管理界面。
兩個用戶,ClientID分別就是上面業務服務器模擬的兩臺設備。
4.簡單流程圖
5.其餘
最後多說兩句,一個產品的業務邏輯和業務需求的前期確認是跟一開始的Topic設計是相關的。Topic若是一開始設計的很差,後面的業務就很難進行擴展了。只能往EMQ增長邏輯判斷,我以爲是很沒有必要的。不少能夠靠Topic的巧妙設計來避開復雜的業務邏輯。
另外,須要不少對設備的統計,操做的處理.例如統計當前主題下訂閱的用戶,踢出主題下的某個用戶,系統推送下發消息等.好比統計用戶,這個我以爲是業務相關的,須要從業務服務器中獲取,可是業務服務器通常沒有這些數據,因此就須要業務服務器Hook到MQTT服務獲取實時在線數.又好比消息下發推送,這個確定是業務服務器下發消息,好比廣播等,一樣要寫MQTT插件.
固然,這個是我的的想法。期待下一篇博客 業務系統設計2。