• EMQ X:认证


    简介

    身份认证是大多数应用的重要组成部分,MQTT 协议支持用户名密码认证,启用身份认证能有效阻止非法客户端的连接。

    EMQ X 中的认证指的是当一个客户端连接到 EMQ X 的时候,通过服务器端的配置来控制客户端连接服务器的权限。

    EMQ X 的认证支持包括两个层面:

    • MQTT 协议本身在 CONNECT 报文中指定用户名和密码,EMQ X 以插件形式支持基于 Username、ClientID、HTTP、JWT、LDAP 及各类数据库如 MongoDB、MySQL、PostgreSQL、Redis 等多种形式的认证。
    • 在传输层上,TLS 可以保证使用客户端证书的客户端到服务器的身份验证,并确保服务器向客户端验证服 务器证书。也支持基于 PSK 的 TLS/DTLS 认证。

    认证方式

    EMQ X 支持的认证方式:

    内置数据源:

    • Username 认证
    • Cliend ID 认证

    外部数据库:

    • LDAP 认证
    • MySQL 认证
    • PostgreSQL 认证
    • Redis 认证
    • MongoDB 认证

    其他:

    • HTTP 认证
    • JWT 认证

    认证结果

    任何一种认证方式最终都会返回一个结果:

    • 认证成功:经过比对客户端认证成功
    • 认证失败:经过比对客户端认证失败,数据源中密码与当前密码不一致
    • 忽略认证(ignore):当前认证方式中未查找到认证数据,无法显式判断结果是成功还是失败,交由认证链下一认证方式或匿名认证来判断

    匿名认证

    EMQ X 默认配置中启用了匿名认证,任何客户端都能接入 EMQ X。

    没有启用认证插件或认证插件没有显式允 许/拒绝(ignore)连接请求时,EMQ X 将根据匿名认证启用情况决定是否允许客户端连接。

    配置匿名认证开关:

    #关闭匿名认证
    vi /etc/emqx/emqx.conf
    
    ## Allow anonymous authentication by default if no auth plugins loaded.
    ## Notice: Disable the option in production deployment!
    ##
    ## Value: true | false
    #改为false
    allow_anonymous = false
    
    #重启emqx
    emqx restart
    

    加密加盐及认证流程

    加密加盐

    EMQ X 多数认证插件中可以启用哈希方法,数据源中仅保存密码密文,保证数据安全。

    启用哈希方法时,用户可以为每个客户端都指定一个 salt(盐)并配置加盐规则,数据库中存储的密码是按照加盐规则与哈希方法处理后的密文。

    以 MySQL 认证为例,加盐规则与哈希方法配置:

    # etc/plugins/emqx_auth_mysql.conf
    ## 不加盐,仅做哈希处理
    auth.mysql.password_hash = sha256
    ## salt 前缀:使用 sha256 加密 salt + 密码 拼接的字符串
    auth.mysql.password_hash = salt,sha256
    ## salt 后缀:使用 sha256 加密 密码 + salt 拼接的字符串
    auth.mysql.password_hash = sha256,salt
    ## pbkdf2 with macfun iterations dklen
    ## macfun: md4, md5, ripemd160, sha, sha224, sha256, sha384, sha512
    ## auth.mysql.password_hash = pbkdf2,sha256,1000,20
    

    如何生成认证信息:

    1. 为每个客户端分用户名、Client ID、密码以及 salt(盐)等信息
    2. 使用与 MySQL 认证相同加盐规则与哈希方法处理客户端信息得到密文
    3. 将客户端信息写入数据库,客户端的密码应当为密文信息

    EMQ X 身份认证流程

    • 根据配置的认证 SQL 结合客户端传入的信息,查询出密码(密文)和 salt(盐)等认证数据,没有查询结果时,认证将终止并返回 ignore 结果
    • 根据配置的加盐规则与哈希方法计算得到密文,没有启用哈希方法则跳过此步
    • 将数据库中存储的密文与当前客户端计算的到的密文进行比对,比对成功则认证通过,否则认证失败

    PostgreSQL 认证功能逻辑图:

    image-20210727134244631

    认证链:

    当同时启用多个认证方式时,EMQ X 将按照插件开启先后顺序进行链式认证:

    • 一旦认证成功,终止认证链并允许客户端接入
    • 一旦认证失败,终止认证链并禁止客户端接入
    • 直到最后一个认证方式仍未通过,根据匿名认证配置判定
      • 匿名认证开启时,允许客户端接入
      • 匿名认证关闭时,禁止客户端接入

    image-20210727134543095

    Mnesia认证

    Mnesia 认证使用 EMQ X 内置 Mnesia 数据库存储客户端 Client ID/Username 与密码,支持通过 HTTP API 管理认证数据。

    Mnesia 认证不依赖外部数据源,使用上足够简单轻量。

    点击启动,让该插件运行

    image-20210727135546146

    Mnesia 认证默认使用 sha256 进行密码哈希加密,可在 etc/plugins/emqx_auth_mnesia.conf 中更改:

    配置哈希方法后,新增的预设认证数据与通过 HTTP API 添加的认证数据将以哈希密文存储在 EMQ X 内置数据库中。

    预设认证数据

    可以通过配置文件预设认证数据,编辑配置文件:etc/plugins/emqx_auth_mnesia.conf

    预设认证数据格式兼容 emqx_auth_clientidemqx_auth_username 插件的配置格式

    ## Password hash.
    ##
    ## Value: plain | md5 | sha | sha256 | sha512
    auth.mnesia.password_hash = sha256
    
    ##--------------------------------------------------------------------
    ## ClientId Authentication
    ##--------------------------------------------------------------------
    
    ## Examples
    auth.client.1.clientid = id
    auth.client.1.password = passwd
    ##auth.client.2.clientid = dev:devid
    ##auth.client.2.password = passwd2
    ##auth.client.3.clientid = app:appid
    ##auth.client.3.password = passwd3
    ##auth.client.4.clientid = client~!@#$%^&*()_+
    ##auth.client.4.password = passwd~!@#$%^&*()_+
    
    ##--------------------------------------------------------------------
    ## Username Authentication
    ##--------------------------------------------------------------------
    
    ## Examples:
    auth.user.1.username = admin
    auth.user.1.password = public
    ##auth.user.2.username = feng@emqtt.io
    ##auth.user.2.password = public
    ##auth.user.3.username = name~!@#$%^&*()_+
    ##auth.user.3.password = pwsswd~!@#$%^&*()_+
    

    插件启动时将读取预设认证数据并加载到 EMQ X 内置数据库中,节点上的认证数据会在此阶段同步至集群中。

    username测试

    测试username,password:

    账号密码为 admin/public

    image-20210727141938487

    增加用户

    image-20210727142706110

    这里增删改查都是完全遵守restful格式,后续不再演示

    查看指定用户user的信息:

    image-20210727142839432

    websocket连接

    image-20210727143052443

    mqttx客户端工具验证

    下载地址:https://github.com/emqx/MQTTX/releases/download/v1.6.0/MQTTX.Setup.1.6.0.exe

    image-20210727145755109

    连接成功:

    image-20210727145820907

    添加一个订阅者:

    image-20210727150222458

    client_id认证

    在前面,我添加了一个client_id信息,账号id为id,密码为passwd

    使用mqttx来验证client_id认证方式:

    这里注意client_id和password填入自己配置的新,这里尽管username没有,但是必须填入一个任意的值,为空则会连接失败

    image-20210727150620583

    http认证

    HTTP 认证使用外部自建 HTTP 应用认证数据源,根据 HTTP API 返回的数据判定认证结果,能够实现复杂的认证鉴权逻辑。

    插件:

    emqx_auth_http  
    

    emqx_auth_http 插件同时包含 ACL 功能,可通过注释禁用。

    认证原理

    EMQ X 在设备连接事件中使用当前客户端相关信息作为参数,向用户自定义的认证服务发起请求查询权限,通过返回的 HTTP 响应状态码 (HTTP statusCode) 来处理认证请求。

    • 认证失败:API 返回 4xx 状态码
    • 认证成功:API 返回 200 状态码
    • 忽略认证:API 返回 200 状态码且消息体 ignore

    加盐规则与哈希方法

    HTTP 在请求中传递明文密码,加盐规则与哈希方法取决于 HTTP 应用

    基本使用

    修改配置文件

    开启该插件:

    image-20210727151456033

    编辑http认证配置文件

    vi /etc/emqx/plugins/emqx_auth_http.conf
    
    #其余配置尚未修改,这里就不展示了
    auth.http.auth_req.url = http://192.168.40.128:8991/mqtt/auth
    auth.http.auth_req.method = post
    auth.http.auth_req.headers.content_type = application/x-www-form-urlencoded
    auth.http.auth_req.params = clientid=%c,username=%u,password=%P
    

    你可以在认证请求中使用以下占位符,请求时 EMQ X 将自动填充为客户端信息:

    • %u:用户名
    • %c:Client ID
    • %a:客户端 IP 地址
    • %r:客户端接入协议
    • %P:明文密码
    • %p:客户端端口
    • %C:TLS 证书公用名(证书的域名或子域名),仅当 TLS 连接时有效
    • %d:TLS 证书 subject,仅当 TLS 连接时有效

    开发认证服务

    这里基于springboot快速开发一套认证服务

    application.yml

    server:
      port: 8991
    spring:
      application:
        name: emq-demo
    

    AuthController.java

    @RestController
    @RequestMapping("/mqtt")
    public class AuthController {
    
        Logger logger = LoggerFactory.getLogger(AuthController.class);
    
        Map<String, String> userMap = new HashMap<>();
    
        @PostConstruct
        public void init(){
            userMap.put("user1","user1");
            userMap.put("user2","user2");
        }
    
    
        @PostMapping("/auth")
        public ResponseEntity<HttpStatus> auth(String username, String clientid, String password){
            logger.info("开始进入auth方法");
            logger.info("username:{}; clientid:{}; password:{}", username, clientid, password);
            String passwd = userMap.get(username);
            if(!StringUtils.hasLength(passwd)){
                return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
            }
            return !password.equals(passwd) ? new ResponseEntity<>(HttpStatus.UNAUTHORIZED) : new ResponseEntity<>(HttpStatus.OK);
        }
    }
    

    打包后,传到服务器并启动

    测试http认证

    image-20210727153912616

    连接成功:

    springboot认证服务日志:

    image-20210727153951963

    emqx认证就介绍到这里,关于其他的认证方式可以参考官方文档:https://docs.emqx.cn/broker/v4.3/advanced/auth.html#认证方式

  • 相关阅读:
    回调函数设计方法
    C 时间函数总结
    linux多线程全面解析
    从为知笔记收费说起
    C++中strftime()的详细说明
    arguments.callee
    arguments 对象
    学习闭包
    this的call,apply,bind的方法总结--追梦子
    this指向--取自追梦子的文章
  • 原文地址:https://www.cnblogs.com/wwjj4811/p/15066248.html
Copyright © 2020-2023  润新知