ActiveMQ:拦截发布到某个主题

时间:2018-04-05 11:56:40

标签: java kotlin activemq

我正在使用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(),也没有被调用。

那么......当客户发布到某个主题时,我如何拦截?

1 个答案:

答案 0 :(得分:0)

经过一些搜索源代码和一些重要的方法,看到他们什么时候被调用以及他们收到了什么,我学到了两件让我做我想做的事情:

  1. 发布的主题封装在邮件中。生产者不会注册发布到某个主题,它只是注册发布到任何主题。经纪人本身不知道哪个主题,这是在逐个消息的基础上处理的。所以我第一次尝试限制addProducer()中的主题是徒劳的,因为 nobody 还知道这个主题。

  2. 发布链中用户名和主题都可用的最早点是addDestination()。首先可以在send()中知道该主题,但您没有该用户。可以通过持久保存上下文的用户名来进行授权,但我不喜欢状态。所以我将授权放入addDestination(),它可以工作。

  3. 但是,这里有一个潜在的警告。根据文档,如果目标尚不存在,则仅调用addDestination()。我可以在有限的时间内完成的所有测试都证实,即使有人订阅了该主题,发布也是如此。但是如果生产者保持持久连接可能会有所不同,所以要小心使用这个解决方案。