ActiveMQ版本 :5.9
ActiveMQ支持可插拔的安全机制,用以在不同的provider之间切换。
JAAS认证插件
JAAS(Java Authentication and Authorization Service)也就是java的验证Authentication)、授权
(Authorization)服务。简单来说,验证Authentication就是要验证一个用户的有效性,即用户名、密码是否正确。
授权Authorization就是授予用户某种角色,可以访问哪些资源。JAASAuthentication Plugin依赖标准的JAAS
机制来实现认证。通常情况下,你需要通过设置java.security.auth.login.config系统属性来配置login
modules的配置文件。如果没有指定这个系统属性,那么JAAS Authentication Plugin会缺省使用
login.config作为文件名。
以下是一个login.config文件的例子:
activemq {
org.apache.activemq.jaas.PropertiesLoginModule required
org.apache.activemq.jaas.properties.user="users.properties"
org.apache.activemq.jaas.properties.group="groups.properties";
};
users.properties
admin=admin
user=sky
guest=sky
group.properties
admins=admin
users=user
guests=guest
这个login.config文件中设置了两个属性:
- org.apache.activemq.jaas.properties.user
- org.apache.activemq.jaas.properties.group
分别用来指向user.properties和group.properties文件。需要注意的是,PropertiesLoginModule使用本地文件的查找方式,而且查找时采用的base directory是login.config文件所在的目录。因此这个login.config说明user.properties和group.properties文件存放在跟login.config文件相同的目录里。(activemq 5.9 默认提供了以上的配置文件)以下是activemq.xml配置的一个例子:
<!-- sky -->
<plugins> <!-- Lets configure a destination based authorization mechanism
采用JAAS的管理机制来配置各种角色的权限
-->
<!-- use JAAS to authenticate using the login.config file on the classpath to configure JAAS . -->
<jaasAuthenticationPlugin configuration="activemq" />
<authorizationPlugin>
<map>
<authorizationMap>
<authorizationEntries>
<authorizationEntry queue=">" read="admins" write="admins" admin="admins" />
<authorizationEntry queue="USERS.>" read="users" write="admins" admin="admins" />
<authorizationEntry queue="GUEST.>" read="guests" write="guests,users" admin="guests,users" />
<authorizationEntry queue="TEST.*" read="guests" write="guests" />
<authorizationEntry topic=">" read="admins" write="admins" admin="admins" />
<!-- 表示通配符,例如USERS.>表示以USERS.开头的主题,>表示所有主题,read表示读的权限,write表示写的权限,admin表示角色组
-->
<authorizationEntry topic="USERS.>" read="users" write="users" admin="users" />
<authorizationEntry topic="GUEST.>" read="guests" write="guests,users" admin="guests,users" />
<authorizationEntry topic="ActiveMQ.Advisory.>" read="guests,users" write="guests,users" admin="guests,users"/>
</authorizationEntries>
<!-- let's assign roles to temporary destinations. comment this entry if we don't want any roles assigned to temp destinations -->
<tempDestinationAuthorizationEntry>
<tempDestinationAuthorizationEntry
read="tempDestinationAdmins" write="tempDestinationAdmins"
admin="tempDestinationAdmins" />
</tempDestinationAuthorizationEntry>
</authorizationMap>
</map>
</authorizationPlugin>
</plugins>
基于以上的配置,在JAAS的LoginContext中会使用login.config中activemq中配置的PropertiesLoginModule来进行登陆。
针对不同的queue或者topic设置了可以进行操作的组。里面主要涉及三种操作:read, write, admin
- read:可以从queue或者topic里面接收消息
- write:可以向queue或者topic发送消息
- admin:可以创建queue或者topic(可能还有别的功能)
例如:
- <authorizationEntry queue=">" read="admins" write="admins" admin="admins" />。 ">"是通配符的意思,也就是admins组的角色,拥有read、write、admin的权限。
- <authorizationEntry queue="USERS.>" read="users" write="admins" admin="admins" /> 。queue名称以"USERS."开头的,users组只拥有读权限,即只能收消息,不能发消息。
简单认证插件
SimpleAuthentication Plugin适用于简单的认证需求,或者用于建立测试环境。它允许在XML配置文件中指定用户、用户组和密码等信息。(该文件位于: %ACTIVEMQ_HOME%\conf\ activemq.xml, D:\sun_java\activemq\apache-activemq-5.9.0\conf )<plugins>
...
<simpleAuthenticationPlugin>
<users>
<authenticationUser username="system" password="manager" groups="users,admins"/>
<authenticationUser username="user" password="password" groups="users"/>
<authenticationUser username="guest" password="password" groups="guests"/>
</users>
</simpleAuthenticationPlugin>
</plugins>
下面是基于JASS认证插件的配置,首先启动activemq服务:
jsm.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<description>JMS高级应用配置(NON_PERSISTENT,DURIABLE,SELECTOR)</description>
<!-- ActiveMQ 连接工厂 -->
<bean id="advancedConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="${jms.broker_url}" />
<property name="userName" value="${jms.userName}" />
<property name="password" value="${jms.password}" />
<!-- 对PERSISTENT的消息进行异步发送(NON_PERSISTENT消息默认异步发送) -->
<!-- <property name="useAsyncSend" value="true" /> -->
</bean>
<!-- 持久化主题订阅者ActiveMQ 连接工厂 -->
<bean id="advancedTopicConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="${jms.broker_url}" />
<!-- Durable订阅者必须设置ClientId -->
<property name="clientID" value="${jms.client_id}" />
<property name="userName" value="${jms.userName}" />
<property name="password" value="${jms.password}" />
</bean>
<!-- Spring Caching 连接工厂 -->
<bean id="advancedCachingConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory" ref="advancedConnectionFactory" />
<property name="sessionCacheSize" value="10" />
</bean>
<!-- Queue定义 -->
<bean id="advancedNotifyQueue" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="USERS.advanced.queue" />
</bean>
<!-- Topic定义 -->
<bean id="advancedNotifyTopic" class="org.apache.activemq.command.ActiveMQTopic">
<constructor-arg value="USERS.advanced.topic" />
</bean>
<!-- Spring JMS Template -->
<bean id="advancedJmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="advancedCachingConnectionFactory" />
<!-- 使 deliveryMode, priority, timeToLive设置生效-->
<property name="explicitQosEnabled" value="true" />
<!-- 设置NON_PERSISTENT模式, 默认为PERSISTENT -->
<property name="deliveryPersistent" value="false" />
<!-- 设置优先级, 默认为4 -->
<property name="priority" value="9" />
</bean>
<!-- 使用Spring JmsTemplate的消息生产者 -->
<bean id="advancedNotifyMessageProducer" class="com.goldpalm.sgyl.api.jms.AdvancedNotifyMessageProducer">
<property name="jmsTemplate" ref="advancedJmsTemplate" />
<property name="notifyQueue" ref="advancedNotifyQueue" />
<property name="notifyTopic" ref="advancedNotifyTopic" />
</bean>
<!-- 异步接收Queue消息Container -->
<bean id="advancedQueueContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="advancedConnectionFactory" />
<property name="destination" ref="advancedNotifyQueue" />
<property name="messageListener" ref="advancedNotifyMessageListener" />
<!-- 初始5个Consumer, 可动态扩展到10 -->
<property name="concurrentConsumers" value="5" />
<property name="maxConcurrentConsumers" value="10" />
<!-- 设置消息确认模式为Client -->
<property name="sessionAcknowledgeModeName" value="CLIENT_ACKNOWLEDGE" />
</bean>
<!-- 异步接收Topic消息Container -->
<bean id="advancedTopicContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="advancedTopicConnectionFactory" />
<property name="destination" ref="advancedNotifyTopic" />
<property name="messageListener" ref="advancedNotifyMessageListener" />
<!-- JMS Selector消息过滤器 -->
<property name="messageSelector" value="objectType='user'" />
<!-- 持久化订阅者 -->
<property name="subscriptionDurable" value="true" />
</bean>
<!-- 异步接收消息处理类 -->
<bean id="advancedNotifyMessageListener" class="com.goldpalm.sgyl.api.jms.AdvancedNotifyMessageListener" />
</beans>
jsm.properties
#activemq settings
#vm broker
#jms.broker_url=vm://showcase?broker.persistent=false&broker.useJmx=false&broker.schedulerSupport=false
#localhost broker
jms.broker_url=tcp://localhost:61616
#network of brokers
#jms.broker_url=failover://(tcp://mqremote1:61616,tcp://mqremote2:61616)?randomize=false&initialReconnectDelay=100&timeout=5000
jms.client_id=durableTopicListenerDemo
#jmx settings
jmx.rmi_port=2099
#demo settings
server.node_name=default
server.addr=localhost
jms.userName=user
jms.password=sky
当我们不使用用户名密码连接时,console控制台会打印:WARN [DefaultMessageListenerContainer.java:888] - Could not refresh JMS Connection for destination 'queue://q.notify' - retrying in 5000 ms. Cause: User name [null] or password is invalid.
当使用用户名为user,密码为sky的账户连接时,如果我们向topic中发送消息,就会提示报错:org.springframework.jms.JmsSecurityException: User user is not authorized to write to: queue://USERS.advanced.queue; nested exception is javax.jms.JMSSecurityException: User user is not authorized to write to: queue://USERS.advanced.queue