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(可能还有别的功能)
这些文件配制好时候,ActiveMQ就具有了基本的安全机制,当Client(生产者和消费者)连接ActiveMQ需要使用账号,还可以限制具体的Client对于某个/某些Topic/Queue的操作权限.
例如:
- <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