• 周六. 10月 8th, 2022

5G编程聚合网

5G时代下一个聚合的编程学习网

热门标签

EMQ X:认证

admin

11月 28, 2021

简介

身份认证是大多数应用的重要组成部分,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 = [email protected]#$%^&*()_+
##auth.client.4.password = [email protected]#$%^&*()_+

##--------------------------------------------------------------------
## Username Authentication
##--------------------------------------------------------------------

## Examples:
auth.user.1.username = admin
auth.user.1.password = public
##auth.user.2.username = [email protected]
##auth.user.2.password = public
##auth.user.3.username = [email protected]#$%^&*()_+
##auth.user.3.password = [email protected]#$%^&*()_+

插件启动时将读取预设认证数据并加载到 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#认证方式

发表回复

您的电子邮箱地址不会被公开。