「这是我参与11月更文挑战的第8天,活动详情查看:2021最后一次更文挑战」。
往前文章:
HTTP 认证使用外部自建 HTTP 应用认证数据源,根据 HTTP API 返回的数据判定认证结果,能够实现复杂的认证鉴权逻辑。启用该功能需要将 emqx_auth_http 插件启用,并且修改该插件的配置文件,在里面指定HTTP认证接口的url。 emqx_auth_http 插件同时还包含了ACL的功能,我们暂时还用不上,通过注释将其禁用。
1:在Dashboard中中开启 emqx_auth_http 插件,同时为了避免误判我们可以停止通过username,clientID 进行认证的插件 emqx_auth_clientid , emqx_auth_username
1. 认证原理
EMQ X 在设备连接事件中使用当前客户端相关信息作为参数,向用户自定义的认证服务发起请求查询权限,
通过返回的 HTTP 响应状态码 (HTTP statusCode) 来处理认证请求。
- 认证失败:API 返回 4xx 状态码
- 认证成功:API 返回 200 状态码
- 忽略认证:API 返回 200 状态码且消息体 ignore
2. HTTP 请求信息
HTTP API 基础请求信息,配置证书、请求头与重试规则。
# etc/plugins/emqx_auth_http.conf
## 启用 HTTPS 所需证书信息
## auth.http.ssl.cacertfile = etc/certs/ca.pem
## auth.http.ssl.certfile = etc/certs/client-cert.pem
## auth.http.ssl.keyfile = etc/certs/client-key.pem
## 请求头设置
## auth.http.header.Accept = */*
## 重试设置
auth.http.request.retry_times = 3
auth.http.request.retry_interval = 1s
auth.http.request.retry_backoff = 2.0
复制代码
加盐规则与哈希方法
HTTP 在请求中传递明文密码,加盐规则与哈希方法取决于 HTTP 应用。
3. 认证请求
进行身份认证时,EMQ X 将使用当前客户端信息填充并发起用户配置的认证查询请求,查询出该客户端在
HTTP 服务器端的认证数据。
打开etc/plugins/emqx_auth_http.conf配置文件,通过修改如下内容:修改完成后需要重启EMQX服务
# etc/plugins/emqx_auth_http.conf
## 请求地址 填写 http 验证服务的地址
auth.http.auth_req = http://192.168.10.20:8991/mqtt/auth
## HTTP 请求方法
## Value: post | get | put
auth.http.auth_req.method = post
## 请求参数
auth.http.auth_req.params = clientid=%c,username=%u,password=%P
复制代码
HTTP 请求方法为 GET 时,请求参数将以 URL 查询字符串的形式传递;POST、PUT 请求则将请求参数以普通
表单形式提交(content-type 为 x-www-form-urlencoded)。
你可以在认证请求中使用以下占位符,请求时 EMQ X 将自动填充为客户端信息:
- %u:用户名
- %c:Client ID
- %a:客户端 IP 地址
- %r:客户端接入协议
- %P:明文密码
- %p:客户端端口
- %C:TLS 证书公用名(证书的域名或子域名),仅当 TLS 连接时有效
- %d:TLS 证书 subject,仅当 TLS 连接时有效
推荐使用 POST 与 PUT 方法,使用 GET 方法时明文密码可能会随 URL 被记录到传输过程中的服务器日志中。
4. 认证服务开发
创建基于springboot的应用程序: emq-demo
pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>emq-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>emq-demo</name>
<description>emq demo演示</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
复制代码
创建application.yml配置文件并配置
server:
port: 8991
spring:
application:
name: emq-demo
复制代码
创建Controller
package com.example.emqdemo.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/mqtt")
@Slf4j
public class AuthController {
private Map<String,String> users;
@PostConstruct
public void init(){
users = new HashMap<>();
//实际的密码应该是密文,mqtt的http认证组件传输过来的密码是明文,
// 我们需要自己进行加密验证
users.put("user","123456");
users.put("emq-client2","123456");
users.put("emq-client3","123456");
}
@PostMapping("auth")
public ResponseEntity<?> auth(@RequestParam("clientid") String clientid,
@RequestParam("username") String username,
@RequestParam("password") String password) {
log.info("emqx认证组件调用自定义的认证服务开始认证,clientid={},username={},password= {}",clientid,username,password);
//在此处可以进行复杂也的认证逻辑,但是我们为了演示方便做一个固定操作
String userPassword = users.get(username);
if (StringUtils.isEmpty(userPassword) || !userPassword.equals(password)) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(HttpStatus.UNAUTHORIZED);
}
return ResponseEntity.ok(HttpStatus.OK);
}
}
复制代码
MQTTX客户端验证
这个地方的Client-ID随便输入,因为在验证的代码里没有对该字段做校验,之后点连接,发现会连接成功,然
后可以去自定义的认证服务中查看控制台输出,证明基于外部的http验证接口生效了。在实际项目开发过程中,
HTTP接口校验的代码不会这么简单,账号和密码之类的数据肯定会存在后端数据库中,代码会通过传入的数据和
数据库中的数据做校验,如果成功才会校验成功,否则校验失败。
成功后可以在 emqx 控制台看到连接的客户端信息
当然EMQ X除了支持我们之前讲过的几种认证方式外,还支持其他的认证方式,比如:MySQL认证、
PostgreSQL认证、Redis认证、MongoDB认证,对于其他这些认证方式只需要开启对应的EMQ X插件并且配置对
应的配置文件,将对应的数据保存到相应的数据源即可。
近期评论