ActiveMQ支持可插拔的安全机制,用以在不同的provider之间切换 ,授权认证支持三种方式:
1.simpleAuthenticationPlugin
只需要在\conf\ActiveMQ .xml 中加入下列配置就可
<plugins>
<simpleAuthenticationPlugin>
<users>
<authenticationUser username="system" password="manager" groups="users,admins"/>
</users>
</simpleAuthenticationPlugin>
</plugins>
plugins 标签需放在broker标签里面
上述配置的意思添加授权用户 system 密码manager 该用户分组为users 和admins
2.使用JAAS 认证
\conf\login.config
activemq-domain {
org.apache.activemq.jaas.PropertiesLoginModule required debug=true
org.apache.activemq.jaas.properties.user="users.properties"
org.apache.activemq.jaas.properties.group="groups.properties";
};
debug=true : 在认证过程发生异常,可以输出详细的异常信息;
reload=true : 在增加用户(组)或变更用户(组)及密码后,刷新内存配置信息(不需要重启 activemq 服务)
users.properties 用户配置
groups.properties 用户权限组配置
plugins>
<jaasAuthenticationPlugin configuration="activemq-domain" />
<authorizationPlugin>
<map>
<authorizationMap>
<authorizationEntries>
<authorizationEntry queue=">" read="admins" write="admins" admin="admins" />
<authorizationEntry queue="USERS.>" read="users" write="users" admin="users" />
<authorizationEntry queue="GUEST.>" read="guests" write="guests,users" admin="guests,users" />
<authorizationEntry topic=">" read="admins" write="admins" admin="admins" />
<authorizationEntry topic="test.>" read="test" write="test" admin="test" />
<authorizationEntry topic="GUEST.>" read="guests" write="guests,users" admin="guests,users" />
<authorizationEntry topic="ActiveMQ.Advisory.>" read="guests,users,test" write="guests,users,test" admin="guests,users,test"/>
</authorizationEntries>
</authorizationMap>
</map>
</authorizationPlugin>
</plugins>
授权配置
- read:可以从queue或者topic里面接收消息
- write:可以向queue或者topic发送消息
- admin:可以创建queue或者topic(可能还有别的功能)
这里需要注意的点是 queue topic 代表点对点 或者 pub/sub端的名称
queue和topic 可使用通配符 > 或者*来表示
3.自定义认证方式
建立maven 项目导入依赖
<!-- activemq 驱动 -->
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-broker</artifactId>
<version>5.15.12</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-jaas</artifactId>
<version>5.15.12</version>
</dependency>
<!-- mysql 驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.18</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.26.RELEASE</version>
</dependency>
<!-- logs -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.7</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.1.7</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-access</artifactId>
<version>1.1.7</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.7</version>
</dependency>
自定义broker认证
package com.kedalo.borker.plugin;
import org.apache.activemq.broker.Broker;
import org.apache.activemq.broker.BrokerPlugin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import com.kedalo.auth.plugin.LoginAuthPlugin;
/**
* @author lyl
*
* @desc 自定义broker
*
* 2020年4月16日上午11:37:00
*/
public class AuthBroker implements BrokerPlugin {
final Logger log = LoggerFactory.getLogger(AuthBroker.class);
JdbcTemplate jdbcTemplate;
public AuthBroker(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public Broker installPlugin(Broker arg0) throws Exception {
log.info("=============== 初始化认证 ============================");
return new LoginAuthPlugin(arg0,jdbcTemplate);
}
}
这里认证组件
package com.kedalo.auth.plugin;
import java.security.Principal;
import java.security.cert.X509Certificate;
import java.util.HashSet;
import java.util.Set;
import org.apache.activemq.broker.Broker;
import org.apache.activemq.broker.ConnectionContext;
import org.apache.activemq.command.ConnectionInfo;
import org.apache.activemq.jaas.GroupPrincipal;
import org.apache.activemq.security.AbstractAuthenticationBroker;
import org.apache.activemq.security.SecurityContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import com.kedalo.auth.db.DBMapper;
import com.kedalo.auth.model.User;
/**
* @author lyl
*
* @desc 认证组件
*
* 2020年4月16日上午11:37:18
*/
public class LoginAuthPlugin extends AbstractAuthenticationBroker {
private JdbcTemplate jdbcTemplate;
final Logger log = LoggerFactory.getLogger(LoginAuthPlugin.class);
private DBMapper db = null;
public LoginAuthPlugin(Broker next,JdbcTemplate jdbcTemplate) {
super(next);
this.jdbcTemplate = jdbcTemplate;
db = DBMapper.getInstance(jdbcTemplate);
}
@Override
public SecurityContext authenticate(String username, String password, X509Certificate[] arg2) throws SecurityException {
SecurityContext securityContext = null;
User user = db.login(username, password);
log.info("username:{} password:{}",username,password);
//验证用户信息
if (user == null) {
throw new SecurityException("用户名或者密码错误!");
}
log.info("group:{}",user.getGroup());
securityContext = new SecurityContext(username) {
@Override
public Set<Principal> getPrincipals() {
Set<Principal> groups = new HashSet<Principal>();
groups.add(new GroupPrincipal(user.getGroup()));
return groups;
}
};
return securityContext;
}
/**
* 创建连接的时候拦截
*
* @param context
* @param info
* @throws Exception
*/
@Override
public void addConnection(ConnectionContext context, ConnectionInfo info) throws Exception {
SecurityContext securityContext = context.getSecurityContext();
if (securityContext == null) {
securityContext = authenticate(info.getUserName(), info.getPassword(), null);
context.setSecurityContext(securityContext);
securityContexts.add(securityContext);
}
try {
super.addConnection(context, info);
} catch (Exception e) {
securityContexts.remove(securityContext);
context.setSecurityContext(null);
e.printStackTrace();
throw new Exception("用户权限不足!");
}
}
}
Mapper
package com.kedalo.auth.db;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import com.kedalo.auth.model.User;
import com.kedalo.auth.util.StringUtil;
/**
* @author lyl
*
* @desc 查询
*
* 2020年4月16日上午11:54:08
*/
public class DBMapper {
private static DBMapper INSTANCE;
JdbcTemplate jdbcTemplate;
final Logger log = LoggerFactory.getLogger(DBMapper.class);
public DBMapper(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public static DBMapper getInstance(JdbcTemplate jdbcTemplate) {
if (INSTANCE == null)
synchronized(DBMapper.class){
INSTANCE = new DBMapper(jdbcTemplate);
}
return INSTANCE;
}
public User login(String username,String password) {
String sql = "select a.*,ug.`group` from kedalo_user a " +
" LEFT JOIN kedalo_user_group ug on a.user_id = ug.user_id where username= ? and password= ?";
try {
System.out.println(jdbcTemplate == null);
User user = jdbcTemplate.queryForObject(sql, new Object[]{username,StringUtil.md5(password)}, new BeanPropertyRowMapper<User>(User.class));
return user;
} catch (EmptyResultDataAccessException e) {
log.error("登录出现异常:"+e);
return null;
}
}
}
我这里建立2 个表一个user表一个分组表
自定义认证代码到此
接下来需要在activeMQ.xml 中配置我们的认证
<plugins>
<authorizationPlugin>
<map>
<authorizationMap>
<authorizationEntries>
<authorizationEntry queue=">" read="admins" write="admins" admin="admins" />
<authorizationEntry queue="USERS.>" read="users" write="users" admin="users" />
<authorizationEntry queue="GUEST.>" read="guests" write="guests,users" admin="guests,users" />
<authorizationEntry topic=">" read="admins" write="admins" admin="admins" />
<authorizationEntry topic="test.>" read="test" write="test" admin="test" />
<authorizationEntry topic="GUEST.>" read="guests" write="guests,users" admin="guests,users" />
<authorizationEntry topic="ActiveMQ.Advisory.>" read="guests,users,test" write="guests,users,test" admin="guests,users,test"/>
</authorizationEntries>
</authorizationMap>
</map>
</authorizationPlugin>
<bean xmlns="http://www.springframework.org/schema/beans" id="myPlugin" class="com.kedalo.borker.plugin.AuthBroker">
<constructor-arg>
<ref bean="jdbcTemplate"/>
</constructor-arg>
</bean>
</plugins>
plugins 标签需放在broker标签里面
<!-- mysql数据库数据源-->
<bean id="mySqlDataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
JDBC
<!-- 增加jdbcTemplate-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" abstract="false"
lazy-init="false" autowire="default" >
<property name="dataSource">
<ref bean="mySqlDataSource" />
</property>
</bean>
我们的配置文件 db.properties
<!-- Allows us to use system properties as variables in this configuration file -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>file:${activemq.conf}/credentials.properties</value>
<value>file:${activemq.conf}/db.properties</value>
</list>
</property>
</bean>
activeMQ配置完毕接下来需要放我们的jar包
mysql-connector-java-8.0.18.jar 放置在activeMQ/lib/ 文件夹中
spring-jdbc-4.3.26.RELEASE.jar 放置在activeMQ/lib/ optional/文件夹中
slf4j-api-1.7.7.jar logback-core-1.1.7.jar logback-access-1.1.7.jar logback-classic-1.1.7.jar 放置在activeMQ/lib/ 文件夹中
启动activeMq
启动成功
我们来测试一下写一个链接DEMO
package activemqClient.activemqClient;
import java.io.IOException;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;
import org.apache.activemq.ActiveMQConnectionFactory;
/**
* Hello world!
*
*/
public class Sub {
public static void main( String[] args ) throws JMSException, IOException {
//创建连接工厂
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("root","1234563","tcp://127.0.0.1:61616");
//创建连接
Connection connection = connectionFactory.createConnection();
//启动
connection.start();
//创建session对象 false表示是否自动提交;
Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
//创建队列 des的子类!
Topic topic = session.createTopic("qtest.f");
//创建消费者
MessageConsumer messageConsumer = session.createConsumer(topic);
messageConsumer.setMessageListener(new MessageListener() {
public void onMessage(Message message) {
TextMessage textMessage = (TextMessage) message;
try {
System.out.println("PUB:"+textMessage.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
});
System.in.read();
//关闭资源
messageConsumer.close();
session.close();
connection.close();
}
}
这里我故意写错密码看看返回
然后在订阅没有权限的topic
关于权限这款重点中的重点
<authorizationEntry topic="ActiveMQ.Advisory.>" read="guests,users,test" write="guests,users,test" admin="guests,users,test"/>
这个一定要配置上 因为客户端一建立连接首先的请求就是 tcp://ActiveMQ.Advisory 所以认证+JAAS 这块需要设置所有的分组
来源:oschina
链接:https://my.oschina.net/u/167092/blog/3236914