下载
https://github.com/jpmens/mosquitto-auth-plug/
解压 放到下面目录下
cd /root/mosquitto-auth-plug
cp config.mk.in config.mk
然后编辑 config.mk
BACKEND_MYSQL ?= yes
MOSQUITTO_SRC =/root/mosquitto-1.6.7 ##这是mosquitto源码目录
安装依赖
yum install gcc-c++
yum install libuuid-devel
yum install mysql+±devel.x86_64
yum install openssl-devel
yum install libc-ares-dev
编译
make
auth-plug.c:601:5: error: conflicting types for ‘mosquitto_auth_acl_check’
重要::
编译插件时报这个错误给搞死
根据文件查找对比插件的auth-plug.c 跟 源码里的mosquitto_plugin.h,其实auth-plug.c的那几个鉴权方法就相当于是重写mosquitto_plugin.h里的,
对比发现auth-plug.c 里的那些方法如‘mosquitto_auth_acl_check’里的一个参数struct mosquitto *client 这个不能有const,把const 去掉,不然会报类型不匹配无法编译
然后再make
在目录下得到auth-plug.so
把auth-plug.so放到/etc/mosquitto/plugin/ 里
配置 mosquitto
编辑mosquitto.conf
##不允许匿名访问
allow_anonymous false
auth_plugin /etc/mosquitto/plugin/auth-plug.so
auth_opt_backends mysql
auth_opt_host localhost
auth_opt_port 3306
auth_opt_user root
auth_opt_pass 123456
auth_opt_dbname mosquitto
auth_opt_userquery SELECT pw FROM users WHERE username = ‘%s’ LIMIT 1
auth_opt_superquery SELECT IFNULL(COUNT(*), 0) FROM users WHERE username = ‘%s’ AND super = 1
auth_opt_aclquery SELECT topic FROM acls WHERE (username = ‘%s’) AND (rw >= %d)
auth_opt_acl_cacheseconds 0 acl 缓存时间 默认300秒 0 表示不缓存
测试时一直报MqttException (128)
这是没有权限 acl表的权限值 要弄成对应的,这里要注意acl的缓存auth_opt_acl_cacheseconds ,否则会有大坑,一直测不准
数据库中ACL表上的读/写值必须在0到7之间变化。
0:无法访问
1:阅读
2:写
3:读写
4:订阅
5:阅读并订阅
6:撰写并订阅
7:读,写和订阅
一般读客户端用户就设置为5
装完后重新启动mosquitto就行了。
以后用户就直接由业务系统直接插入mysql,并且插入对应权限
附上java加密密码的代码
MosquittoPBKDF2.java
package com.dxf.demospringbootoss.mqtt;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.nio.charset.Charset;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.Base64;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* This class implements functionality to generate and validate PBKDF2 hashes
* for mosquitto-auth-plug.
*
* @author Manuel Domínguez-Dorado - manuel.dominguez@enzinatec.es
* @version 1.0
*/
public class MosquittoPBKDF2 {
/**
* This method compares a plain password and a PBKDF2 password (in
* mosquitto-auth-plug format) to know whether the password match the PBKDF2
* hash.
*
* @author Manuel Domínguez Dorado - manuel.dominguez@enzinatec.com
* @param plainPassword Tha plain password to be compared to the PBKDF2
* hash.
* @param hashedPasword The PBKDF2 password in mosquitto-auth-plug format
* (usualli it is stored in a MySQL database).
* @return true, if password matches the PBKDF2 hash. false on the contrary.
* @since 1.0
*/
public boolean isValidPassword(String plainPassword, String hashedPasword) {
String[] encodedPassword = hashedPasword.split("\\$");
int encodedIterations = Integer.parseInt(encodedPassword[2]);
byte[] encodedSalt = encodedPassword[3].getBytes(Charset.forName("UTF-8"));
String encodedHash = encodedPassword[4];
SecretKeyFactory f = null;
try {
f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
} catch (NoSuchAlgorithmException e) {
System.out.println("Need a Java implementation with cryptography.");
}
KeySpec ks = new PBEKeySpec(plainPassword.toCharArray(), encodedSalt, encodedIterations, MosquittoPBKDF2.KEY_LENGTH);
SecretKey s = null;
try {
s = f.generateSecret(ks);
} catch (InvalidKeySpecException e) {
System.out.println("Encoded password is corrupt.");
}
return encodedHash.equals(Base64.getEncoder().encodeToString(s.getEncoded()));
}
/**
* This method creates a new PBKDF2 password (in mosquitto-auth-plug format)
* from a plain password.
*
* @author Manuel Domínguez Dorado - manuel.dominguez@enzinatec.com
* @param plainPassword The plain password used to generate the
* corresponding PBKDF2 password (in mosquitto-auth-plug) format.
* @return The generated PBKDF2 password in mosquitto-auth-plug format
* (usually, it will be stored in a MySQL database).
* @since 1.0
*/
public String createPassword(String plainPassword) {
byte someBytes[] = new byte[MosquittoPBKDF2.SALT_LENGTH];
Random randomGenerator = new Random();
randomGenerator.nextBytes(someBytes);
String encodedSalt = Base64.getEncoder().encodeToString(someBytes);
SecretKeyFactory f = null;
try {
f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(MosquittoPBKDF2.class.getName()).log(Level.SEVERE, null, ex);
}
KeySpec ks = new PBEKeySpec(plainPassword.toCharArray(), encodedSalt.getBytes(), MosquittoPBKDF2.ITERATIONS, MosquittoPBKDF2.KEY_LENGTH);
SecretKey s;
try {
s = f.generateSecret(ks);
String encodedKey = Base64.getEncoder().encodeToString(s.getEncoded());
String hashedKey = "PBKDF2$sha256$" + MosquittoPBKDF2.ITERATIONS + "$" + encodedSalt + "$" + encodedKey;
return hashedKey;
} catch (InvalidKeySpecException ex) {
Logger.getLogger(MosquittoPBKDF2.class.getName()).log(Level.SEVERE, null, ex);
}
return "";
}
private static final int KEY_LENGTH = 24 * 8;
private static final int SALT_LENGTH = 12;
private static final int ITERATIONS = 901;
}
使用
MosquittoPBKDF2 pbkdf2Factory = new MosquittoPBKDF2();
String hashedPassword = pbkdf2Factory.createPassword("123456");