我正在使用MQTT设置ActiveMQ代理,该代理使用外部服务进行用户身份验证。
我想出了如何编写BrokerFilter并将其插入代理,因此涵盖了基础知识。
我甚至可以使用addConsumer()
覆盖限制用户允许订阅的主题。该方法看起来像这样,并起作用:
override fun addConsumer(context: ConnectionContext?, info: ConsumerInfo?): Subscription {
// let connections from the local vm through
return if (isLocalConnection(context!!)) {
super.addConsumer(context, info)
} else {
val username = context?.userName ?: ""
val cameraCode = getTopicElementsFromDestination(info!!.destination).first()
assertUserHasPermissionForCamera(username, cameraCode)
super.addConsumer(context, info)
}
}
所以我认为限制发布与覆盖addProducer()
几乎相同,但我偶然发现了一些问题。
第一个问题是订阅也称为addProducer()
,这至少令人惊讶。但真正令人惊讶的是,调用此方法时ConsumerInfo::destination
始终为null。我进行了广泛的搜索,但是我无法找到从传递给addProducer()
的信息中提取发布主题的方法。在不知道制作人想要发布哪个主题的情况下,我显然无法限制它。
所以我尝试重写messageDelivered()
,认为我可以在发布错误的主题时丢弃该消息,从而实现或多或少相同的效果。根据文档,只要代理收到消息,就应该调用此方法。但是当我向经纪人发送消息时它不会被调用,所以要么我误解了“传递给经纪人的消息”意味着什么或者有些可疑。
我也试过addSession()
,也没有被调用。
那么......当客户发布到某个主题时,我如何拦截?
答案 0 :(得分:0)
经过一些搜索源代码和一些重要的方法,看到他们什么时候被调用以及他们收到了什么,我学到了两件让我做我想做的事情:
发布的主题封装在邮件中。生产者不会注册发布到某个主题,它只是注册发布到任何主题。经纪人本身不知道哪个主题,这是在逐个消息的基础上处理的。所以我第一次尝试限制addProducer()中的主题是徒劳的,因为 nobody 还知道这个主题。
发布链中用户名和主题都可用的最早点是addDestination()。首先可以在send()中知道该主题,但您没有该用户。可以通过持久保存上下文的用户名来进行授权,但我不喜欢状态。所以我将授权放入addDestination(),它可以工作。