热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

物联网架构成长之路(21)-业务服务器设计1

0.前言前段时间忙了其他事了,感觉利用周末的时间效率好低哦。没有平时上班时间的效率高。哈哈哈。这篇博客,主要是物联网业务服务器前期的一些简单设计。主要是设备如何进行登录,从业务服务器那里获取Tok

0.前言
  前段时间忙了其他事了,感觉利用周末的时间效率好低哦。没有平时上班时间的效率高。哈哈哈。这篇博客,主要是物联网业务服务器前期的一些简单设计。主要是设备如何进行登录,从业务服务器那里获取Token后,登陆到MQTT服务器。业务服务器对设备的登录验证,ACL权限验证这两方面。主要是把业务服务器与MQTT服务器联系起来。

  距离上次EMQ学习已经有一段时间了,测试服务器也已经换了。由于一些原因,只能用自己的服务器了。博客中出现的IP或者域名,由于只是测试环境,没有进行过多的限制,有幸看到博客的,请不要搞破坏哦。哈哈哈。/滑稽

  每个人对业务的设计的不同的,我只是根据自己的了解来设计的。有更好的想法,可以在下面评论区,跟我讨论哦。

1.EMQ服务器配置
  本次使用2.3.5版本。直接是从github.com上拉取下来的,然后进行源代码进行安装的。前期开发不用涉及到插件开发,可以直接使用官网提供的二进制包。不然的话,就用源代码自己编译。注意这里如果自己编译的话,Erlang要 R20+版本才可以。自己到http://www.erlang.org 下载新版的Erlang/OTP。

  一切的编译步骤,我在前面的博客有提到,不清楚的可以看我前面的博客。虽然EMQ进行了小版本更新,但是大体的编译流程还是差不多了。这里就不多说了。

  编译后,会在emq-relx目录下生成_rel/emqttd目录。

  我觉得MQTT通信服务器与业务服务器是要尽量分开的,特别是不要在MQTT服务器里做过多的业务处理。所以使用EMQ服务器里面的帐号验证和ACL权限验证。采用的是Redis中间件验证方式。

  由于默认的EMQ服务器是不多帐号密码进行验证和主题的验证。这里我们要开启验证。下面的这些配置是对默认的配置进行的修改。

  (1)data/loaded_plugins 文件

  这里要增加一行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="/>
 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">登录MQTTbutton> <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。

 


推荐阅读
  • DVWA学习笔记系列:深入理解CSRF攻击机制
    DVWA学习笔记系列:深入理解CSRF攻击机制 ... [详细]
  • 深入探索HTTP协议的学习与实践
    在初次访问某个网站时,由于本地没有缓存,服务器会返回一个200状态码的响应,并在响应头中设置Etag和Last-Modified等缓存控制字段。这些字段用于后续请求时验证资源是否已更新,从而提高页面加载速度和减少带宽消耗。本文将深入探讨HTTP缓存机制及其在实际应用中的优化策略,帮助读者更好地理解和运用HTTP协议。 ... [详细]
  • RabbitMQ是使用Erlang编写的一个开源的消息队列,本身支持很多的协议:AMQP,XMPP,SMTP,STOMP,也 ... [详细]
  • Java自学知乎!阿里高级算法专家公开10份资料,涨姿势!
    接口概述:接口是Java语言中的一种引用类型,是方法的集合,所以接口的内部主要就是定义方法,包含常量,抽象方法(JDK ... [详细]
  • 关于我们EMQ是一家全球领先的开源物联网基础设施软件供应商,服务新产业周期的IoT&5G、边缘计算与云计算市场,交付全球领先的开源物联网消息服务器和流处理数据 ... [详细]
  • 深入解析 OpenSSL 生成 SM2 证书:非对称加密技术与数字证书、数字签名的关联分析
    本文深入探讨了 OpenSSL 在生成 SM2 证书过程中的技术细节,重点分析了非对称加密技术在数字证书和数字签名中的应用。非对称加密通过使用公钥和私钥对数据进行加解密,确保了信息传输的安全性。公钥可以公开分发,用于加密数据或验证签名,而私钥则需严格保密,用于解密数据或生成签名。文章详细介绍了 OpenSSL 如何利用这些原理生成 SM2 证书,并讨论了其在实际应用中的安全性和有效性。 ... [详细]
  • Windows环境下RabbitMQ安装详尽指南
    Windows环境下RabbitMQ安装详尽指南 ... [详细]
  • 通过使用七牛云存储服务,本文详细介绍了如何将本地图片高效上传至云端,并实现了内容的便捷管理。借助七牛云的 Python SDK,文章提供了从认证到文件上传的具体代码示例,包括导入必要的库、生成上传凭证以及处理文件路径等关键步骤。此外,还探讨了如何利用七牛云的 URL 安全编码功能,确保数据传输的安全性和可靠性。 ... [详细]
  • 理解和应用HTTP请求中的转发与重定向机制
    在HTTP请求处理过程中,客户端发送请求(通常简称为req),服务器进行相应处理后返回响应(通常简称为res)。理解和应用客户端的转发与重定向机制是前端开发的重要内容。这两种机制在Web开发中具有关键作用,能够有效管理和优化用户请求的处理流程。转发机制允许服务器内部将请求传递给另一个资源,而重定向则指示客户端向新的URL发起新的请求,从而实现页面跳转或资源更新。掌握这些技术有助于提升应用的性能和用户体验。 ... [详细]
  • MySQL索引详解及其优化策略
    本文详细解析了MySQL索引的概念、数据结构及管理方法,并探讨了如何正确使用索引以提升查询性能。文章还深入讲解了联合索引与覆盖索引的应用场景,以及它们在优化数据库性能中的重要作用。此外,通过实例分析,进一步阐述了索引在高读写比系统中的必要性和优势。 ... [详细]
  • FastDFS Nginx 扩展模块的源代码解析与技术剖析
    FastDFS Nginx 扩展模块的源代码解析与技术剖析 ... [详细]
  • 深入解析 Vue 中的 Axios 请求库
    本文深入探讨了 Vue 中的 Axios 请求库,详细解析了其核心功能与使用方法。Axios 是一个基于 Promise 的 HTTP 客户端,支持浏览器和 Node.js 环境。文章首先介绍了 Axios 的基本概念,随后通过具体示例展示了如何在 Vue 项目中集成和使用 Axios 进行数据请求。无论你是初学者还是有经验的开发者,本文都能为你解决 Vue.js 相关问题提供有价值的参考。 ... [详细]
  • C#微信开发入门教程第二篇:新手快速上手指南,含详细视频讲解
    在距离上次课程一个多星期后,我们终于带来了第二讲的内容。虽然原计划是一周一次更新,但由于工作繁忙有所延迟。近期在交流群中发现,一些初学者已经能够熟练调用微信接口,但对微信公众平台的消息接收处理机制还不够了解。因此,本次课程将详细介绍如何高效处理微信公众平台的消息接收,并提供详细的视频讲解,帮助大家快速上手。 ... [详细]
  • 本文推荐了六款高效的Java Web应用开发工具,并详细介绍了它们的实用功能。其中,分布式敏捷开发系统架构“zheng”项目,基于Spring、Spring MVC和MyBatis技术栈,提供了完整的分布式敏捷开发解决方案,支持快速构建高性能的企业级应用。此外,该工具还集成了多种中间件和服务,进一步提升了开发效率和系统的可维护性。 ... [详细]
  • 通过在 Vue Router 中使用 `beforeEach` 导航守卫,可以实现对未登录用户的自动重定向至登录页面的功能。具体实现方法是在导航守卫中检查目标路由的 `meta` 属性,如果该属性中的 `requireAuth` 值为 `true`,则进一步验证用户的登录状态。若用户未登录,则将其重定向到登录页面,确保系统的安全性和用户体验。此外,还可以结合 Vuex 状态管理来存储和验证用户的登录状态,提高代码的可维护性和扩展性。 ... [详细]
author-avatar
自由的成长_563_742_784
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有