上一篇介绍了用户连接时的认证,在我的设计方案中,消息发送者统一调用server,server会与ActiveMQ建立长连接,这样便于对消息进行维护。这里就需要对用户发送权限进行控制,避免客户端直接通过长连接发送消息
关于权限控制可以自己维护,这里给出我的方案:
流程主要是在上一篇的用户登陆后,查询用户的权限,存储到Redis中,修改ActiveMQ,使其在发送前通过查询Redis判断用户是否有发送权限
1.MySQL
在activemq数据库中新建表tb_topic_power
-- ----------------------------
-- Table structure for tb_topic_power
-- ----------------------------
DROP TABLE IF EXISTS `tb_topic_power`;
CREATE TABLE `tb_topic_power` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`userid` int(11) DEFAULT NULL,
`username` varchar(255) DEFAULT NULL,
`topic` varchar(255) DEFAULT NULL,
`send` bit(1) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Records of tb_topic_power
-- ----------------------------
INSERT INTO `tb_topic_power` VALUES ('1', '1', 'admin', 'CKTopicTest', '');
2.修改源码
修改org.apache.activemq.broker.region.Topic
在363行,send方法中添加
if (producerExchange != null && producerExchange.getConnectionContext() != null && producerExchange.getConnectionContext().getClientId() != null && message != null) {
String clientId = producerExchange.getConnectionContext().getUserName();
String topic = message.getDestination().getDestinationPaths()[message.getDestination().getDestinationPaths().length - 1];
{
Object topics = RedisPlugin.getListByKey("TopicOf" + clientId);
boolean b = true;
if (topics == null) {
b = false;
} else {
List<String> topicList = (List<String>) topics;
if (!topicList.contains(topic)) {
b = false;
}
}
if (!b) {
LOG.error("{}无权限发送至{}", clientId, topic);
return;
}
}
}
源码方面即修改完成
3.server中插入数据
List<String> topics = topicPowerService.getTopics(loginParam.getUserName());
if (topics != null && !topics.isEmpty()) {
stringRedisTemplate.opsForList().rightPushAll("TopicOf" + loginParam.getUserName(), topics);
}