mqtt推送,Activemq 扩展插件

业务场景

工作中使用mqtt做推送,activemq作为broker

问题

(1)认证。客户端连接broker需要认证

(2)主题权限。客户只能订阅自己有权限的主题

方案

1 认证

基本原理是activemq支持自定义插件。

公司系统是前后分离的,我们用户在登录后,会将token存与redis。这个认证也是基于redis来认证。

直接上代码:maven项目

1.1 依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.wyl</groupId>
    <artifactId>broker-filter</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <dependencies>
        <!-- activemq -->
        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>activemq-broker</artifactId>
            <version>5.15.8</version>
        </dependency>

        <!-- jedis -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.9.0</version>
        </dependency>
    </dependencies>

</project>

1.2 插件入口类

注意,activemq支持注入的。详见官方文档:http://activemq.apache.org/developing-plugins.html。所以这里的jedisPool,可以在配置文件中注入

package com.yiwo.plugin;

import org.apache.activemq.broker.Broker;
import org.apache.activemq.broker.BrokerPlugin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.JedisPool;

/**
 * broker 过滤器
 *
 * @author wyl
 * @since 2018-12-5
 */
public class BrokerFilter implements BrokerPlugin {

    private Logger logger = LoggerFactory.getLogger(BrokerFilter.class);

    private JedisPool jedisPool;

    public Broker installPlugin(Broker broker) throws Exception {
        logger.info("=============plugin install");
        return new AuthFilter(broker, jedisPool);
    }

    public JedisPool getJedisPool() {
        return jedisPool;
    }

    public void setJedisPool(JedisPool jedisPool) {
        this.jedisPool = jedisPool;
    }
}

1.3 认证过滤类

package com.yiwo.plugin;

import org.apache.activemq.broker.Broker;
import org.apache.activemq.broker.BrokerFilter;
import org.apache.activemq.broker.ConnectionContext;
import org.apache.activemq.broker.region.Subscription;
import org.apache.activemq.command.ConnectionInfo;
import org.apache.activemq.command.ConsumerInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.util.HashMap;
import java.util.Map;

/**
 * broker过滤器
 *
 * @author wyl
 * @since 2018-12-6
 */
public class AuthFilter extends BrokerFilter {

    private Logger logger = LoggerFactory.getLogger(AuthFilter.class);

    private JedisPool jedisPool;

    public AuthFilter(Broker next, JedisPool jedisPool) {
        super(next);
        this.jedisPool = jedisPool;
        logger.info("=============install authFilter");
    }

    @Override
    public void addConnection(ConnectionContext context, ConnectionInfo info) throws Exception {

        long start = System.currentTimeMillis();
        logger.info("=============addConnection");
        logger.info("=============username=" + info.getUserName());
        logger.info("=============password=" + info.getPassword());

        auth(info.getUserName(), info.getPassword());

        long end = System.currentTimeMillis();
        logger.info("=============total time=" + (end - start));

        super.addConnection(context, info);
    }

    /**
     * 认证
     *
     * @param userName 前缀+用户id。如 user:123
     * @param password 登录token。如 48fe6bddc509444c8773760427c52c96
     * @return
     * @author wyl
     * @since 2018-12-6
     */
    private void auth(String userName, String password) {
        if (userName == null || password == null) {
            throw new SecurityException("Invalid  userName or password!");
        }

        String token = getUserRealToken(userName);
        if (!token.equals(password)) {
            throw new SecurityException("Invalid  userName or password!");
        }
    }

    /**
     * 获取用户的token
     *
     * @param username 前缀+用户id。user:123
     * @return
     * @author wyl
     * @since 2018-12-6
     */
    private String getUserRealToken(String username) {
      
//        String token = jedisPool.getResource().get(username);
        Jedis resource = jedisPool.getResource();
        String token = resource.get(username);
        resource.close();

        logger.info("=============token=" + token);
        if (token == null) {
            throw new SecurityException("Invalid  userName or password!");
        }

        return token;
    }

 

坑:

刚开始使用:

String token = jedisPool.getResource().get(username);

获取token。

web端订阅可以成功,但是刷新多次之后就会连不上,经过排查,日志

logger.info("=============token=" + token);

一直打印不出来,说明进入方法getUserRealToken()后有问题,方法中最有可能出问题的就是

String token = jedisPool.getResource().get(username);

猜想是jedisPool链接释放问题,改为:

Jedis resource = jedisPool.getResource();
String token = resource.get(username);
resource.close();

问题解决

1.4 配置插件

由于我们引入了redis的依赖,所以要将其jar包加入activemq的lib目录。

另外activemq-broker已经有了,所有只需要将jedis-2.9.0.jar 和 我们的broker-filter-1.0-SNAPSHOT.jar 上传即可

0fae60d63dd8de44a8b670c42a8e8714413.jpg

 

修改配置文件:activemq/conf/activemq.xml

首先是jedispool,配置在<beans>标签中

<bean id="jedispool"  class="redis.clients.jedis.JedisPool">
  <constructor-arg name="host" value="192.168.0.110"></constructor-arg>
  <constructor-arg name="port" value="6379"></constructor-arg>
</bean>

然后是我们的插件,要配置在<broker>中,并注入jedispool

<plugins>
  <bean xmlns="http://www.springframework.org/schema/beans" id="brokerAuthFilter" class="com.yiwo.plugin.BrokerFilter">
    <property name="jedisPool" ref="jedispool"></property>
  </bean>
</plugins>

 

1.5 重启测试

正确的用户名密码,连接成功

5142eca2140e4792277b20ec7303152bcf7.jpg

 

错误的用户名密码,连接失败

ca3313894cb2a8aad259c8123f1873f2eb7.jpg

 

2 主题权限

原理和认证相同,可以覆盖addConsumer实现,这里不再赘述了

转载于:https://my.oschina.net/u/2935623/blog/2980927

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值