JAVA 开源MQTT服务器 moquette 鉴权源码阅读

mqtt是目前主流iot通信协议,之前用过EMQ,使用erlang写的,我表示看不懂。使用插件鉴权基本可以满足需求。但是不够灵活。最近我发现了JAVA版的mqtt服务器 moquette 底层使用netty实现。非常的轻。

今天我来阅读一下moquette的源代码,以便于使用比较灵活的鉴权方式。
moquette的官方文档没有EMQ详细,好在看得懂Java代码。

首先找到服务器main入口 位于 io.moquette.broker.Server 类

public static void main(String[] args) throws IOException {   
    final Server server = new Server();    
    server.startServer();    
    System.out.println("Server started, version 0.12.1-SNAPSHOT");    //Bind a shutdown hook  
    Runtime.getRuntime().addShutdownHook(new  Thread(server::stopServer));
}

实际上 new Server的时候去读了一些配置,

#*********************************************************************
# Optional Database Authentication
#*********************************************************************
# authenticator_class io.moquette.broker.security.DBAuthenticator
# authenticator.db.driver org.postgresql.Driver# authenticator.db.url  jdbc:postgresql://localhost/test?user=dbuser&password=dbpassword
# authenticator.db.query SELECT PASSWORD FROM ACCOUNT WHERE LOGIN=?# authenticator.db.digest SHA-256

他的配置里面有这样一段示例配置,这就很明显了,我们果断进DBAuthenticator类里面,发现它实现了接口IAuthenticator。这就是一种可插拔的设计方式,如果我们需要自己鉴权,实现这个接口,然后放到配置文件里面就行了,他会通过反射去实例化这个类的。

public interface IAuthenticator {    
    boolean checkValid(String clientId, String username, byte[] password);
}

但是从这个接口上看,传入参数少了一点东西,因为从我的需求上看,有的用户是只允许特定ip登录的,但是这个接口里面并没有提供ip。没关系我们可以打断点往上看。于是我就在DBAuthenticator.checkValid打了一个断点

java.lang.RuntimeException
    at io.moquette.broker.security.DBAuthenticator.checkValid(DBAuthenticator.java:119)
    at io.moquette.broker.MQTTConnection.login(MQTTConnection.java:235)
    at io.moquette.broker.MQTTConnection.processConnect(MQTTConnection.java:162)
    at io.moquette.broker.MQTTConnection.handleMessage(MQTTConnection.java:67)
    at io.moquette.broker.NewNettyMQTTHandler.channelRead(NewNettyMQTTHandler.java:63)

这是调用栈,为了方便复制,我给他抛了一个异常。

然后就一层一层的往下看,发现

  public void channelRead(ChannelHandlerContext ctx, Object message) throws Exception {

这次调用中有传入一个 ctx , 这是netty api给我们提供的一个对象 ,从这个对象里面我们就能拿到ip了

SocketAddress socketAddress =   ctx.pipeline().channel().remoteAddress();
mqttConnection.handleMessage(msg,socketAddress);

然后我再一层一层传下去,最后把接口改一下,就可以在接口里面拿到ip了。

这只是连接时处理的,实际上对ACL的控制,也有同样的一个接口。

public class PermitAllAuthorizatorPolicy implements IAuthorizatorPolicy {    
    @Override    
    public boolean canWrite(Topic topic, String user, String client) {        
        return true;    
    }    
    @Override    
    public boolean canRead(Topic topic, String user, String client) {        
        return true;    
    }
}

拿ip的方式也是一样的,这里就不在赘述了。

总结:通过对IAuthenticator,IAuthorizatorPolicy两个接口进行实现,我们很容易可以做到自定义鉴权

你可能感兴趣的:(iot)