mochi-mqtt/server

How to send topics posted by specific users only to specific subscribed users?

leijux opened this issue · 11 comments

The location of the hook:

server/server.go

Line 1006 in 47162a3

if sub.NoLocal && pk.Origin == cl.ID {

Use scenario:

used to realize the filtering of clients, so that packets are forwarded only to clients that meet the conditions

My current solution:

use OnPacketEncode to filter clients. For clients that do not meet the conditions, I set the FixedHeader.Type field of the packet to packets.WillProperties. However, this approach results in recording error errors.

func (h *Hook) OnPacketEncode(cl *mqtt.Client, pk packets.Packet) packets.Packet {
	switch {
	case pk.TopicName != topicSet && pk.TopicName != topicSetResp:
		return pk
	case pk.Origin == "":
		return pk
	case pk.FixedHeader.Type != packets.Publish:
		return pk
	}
	if pk.TopicName == topicSet && pk.Origin != "mqtt_"+cl.ID { 
		pk.FixedHeader.Type = packets.WillProperties
		return pk
	}
	return pk
}

@leijux If I understand correctly, you want to add some special tags while parsing the packet, so that you can filter them based on these tags during packet processing, right?

If that's the case, I suggest you store your own tag information here in cl.Properties.Props.User, where you can save some Key-Value data for those users you want to filter.

@leijux If I understand correctly, you want to add some special tags while parsing the packet, so that you can filter them based on these tags during packet processing, right?

If that's the case, I suggest you store your own tag information here in cl.Properties.Props.User, where you can save some Key-Value data for those users you want to filter.

用户属性可以作为筛选条件,但是我不知道如何在数据包转发阶段对转发行为进行控制。如下图,主题中有三个客户端,我只想将数据发送给其中的某个客户端,我当前的实现是使用 OnPacketEncode hook 函数,将 包的 FixedHeader.Type 设置为无效的类型,让数据包无法转发出去,但是这样会引发 error 错误,有没有更好的办法,感谢。

image

@leijux 你这种的话,实现hook.OnACLCheck就行了,OnACLCheck会在发送给每个订阅者之前进行鉴权。

In your case, you can implement hook.OnACLCheck, which will authenticate before sending to each subscriber.

@leijux 你这种的话,实现hook.OnACLCheck就行了,OnACLCheck会在发送给每个订阅者之前进行鉴权。

server/server.go

Line 1011 in 6b3b30e

if !s.hooks.OnACLCheck(cl, pk.TopicName, false) {

OnACLCheck 能控制是客户端是否有权限读取这个主题,但是我获取不到是谁发出的数据包,相同主题有时数据包可能要发送给client1,有时可能要发送给client2。

那你只能自己做一些改动了,自己增加一个类似OnACLCheck的钩子方法,比如OnSendToSubscriber,然后可以把发送者的信息(比如ID)保存到pk.Properties里面,将OnACLCheck的参数修改一下。传递的不是topic,而是整个pk。

In that case, you'll need to make some changes yourself. You can add a hook method similar to OnACLCheck, like OnSendToSubscriber. Then you can save the publisher's information (such as ID) into pk.Properties, and pass the entire packet to OnSendToSubscriber.

那你只能自己做一些改动了,自己增加一个类似OnACLCheck的钩子方法,比如OnSendToSubscriber,然后可以把发送者的信息(比如ID)保存到pk.Properties里面,将OnACLCheck的参数修改一下。传递的不是topic,而是整个pk。

感谢,我能在下方的位置增加一个hook方法并提交合并请求吗?

server/server.go

Line 1006 in 47162a3

if sub.NoLocal && pk.Origin == cl.ID {

@leijux 非常可以。我建议增加一个类似OnSendToSubscriber的钩子方法。类似鉴权,不过这个鉴权只针对发送给订阅者时。

@leijux 非常可以。我建议增加一个类似OnSendToSubscriber的钩子方法。类似鉴权,不过这个鉴权只针对发送给订阅者时。

好的,我来考虑实现它。😊

@leijux 我又琢磨了下,是不是可以将OnSendToSubscriber和onAclCheck合并会更好,只需要OnAclCheck的参数改变就可以了,这样就没必要多出一个hook方法,逻辑也更明了

@leijux 我又琢磨了下,是不是可以将OnSendToSubscriber和onAclCheck合并会更好,只需要OnAclCheck的参数改变就可以了,这样就没必要多出一个hook方法,逻辑也更明了

是一个更好的办法,但是会影响api的兼容性。

The cost of changing onAclCheck is still too high. It's possible to use a specific topic to forward to the corresponding clients.

type Hook struct {
             ......
	clients *mqtt.Clients //Introducing mqtt.Clients at Init
}


func (h *Hook) OnPublish(cl *mqtt.Client, pk packets.Packet) (packets.Packet, error) {
	if pk.TopicName != "/a/b/c" {
		return pk, nil
	}
	id := string(pk.Payload)
	if client, ok := h.clients.Get(id); ok {
		client.WritePacket(packets.Packet{
			FixedHeader: packets.FixedHeader{Type: packets.Publish},
			TopicName:   "/x/y/z",
			Payload:     nil,
		})
	}
	return pk, nil
}