使用 WildFly 在 JMS 中进行 JAAS 身份验证:javax.jms.JMSSecurityException:HQ119032:用户:null 没有权限 = 在地址 {2} 上发送
JAAS authentication in JMS using WildFly : javax.jms.JMSSecurityException: HQ119032: User: null doesnt have permission=SEND on address {2}
使用WildFly 9.0.2 final,<hornetq-server>
部分在standalone-full.xml
中定义如下。
<address-settings>
、<acceptors>
和 <connectors>
等部分完全省略,因为我没有更改其中的任何内容。
<hornetq-server>
<security-domain>ProjectRealm</security-domain>
<security-enabled>true</security-enabled>
<journal-file-size>102400</journal-file-size>
<security-settings>
<security-setting match="#">
<permission type="send" roles="ROLE_USER ROLE_ADMIN"/>
<permission type="consume" roles="ROLE_USER ROLE_ADMIN"/>
<permission type="createDurableQueue" roles="ROLE_USER ROLE_ADMIN"/>
<permission type="deleteDurableQueue" roles="ROLE_USER ROLE_ADMIN"/>
<permission type="createNonDurableQueue" roles="ROLE_USER ROLE_ADMIN"/>
<permission type="deleteNonDurableQueue" roles="ROLE_USER ROLE_ADMIN"/>
</security-setting>
</security-settings>
<jms-connection-factories>
<connection-factory name="destinationFactory">
<connectors>
<connector-ref connector-name="http-connector"/>
</connectors>
<entries>
<entry name="java:jboss/exported/jms/destinationFactory"/>
</entries>
</connection-factory>
</jms-connection-factories>
<jms-destinations>
<jms-queue name="userStatusQueue">
<entry name="jms/destination"/>
<entry name="java:jboss/exported/jms/destination"/>
</jms-queue>
</jms-destinations>
</hornetq-server>
它定义了一个名为 destinationFactory
的连接工厂,它使用 http-connector
和一个名为 userStatusQueue
的队列,它们绑定到嵌套的 <entry>
元素中列出的 JNDI 名称.
它还定义了一个安全域。
<security-domain>ProjectRealm</security-domain>
使用
启用安全性(默认)
<security-enabled>true</security-enabled>
在这种情况下,它会导致抛出以下异常。
15:49:28,093 WARNING [javax.enterprise.resource.webcontainer.jsf.lifecycle] (default task-2) java.lang.RuntimeException: javax.jms.JMSSecurityRuntimeException: HQ119032: User: null doesnt have permission=SEND on address {2}: javax.el.ELException: java.lang.RuntimeException: javax.jms.JMSSecurityRuntimeException: HQ119032: User: null doesnt have permission=SEND on address {2}
at com.sun.el.parser.AstValue.invoke(AstValue.java:296)
at com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:304)
at org.jboss.weld.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:40)
at org.jboss.weld.el.WeldMethodExpression.invoke(WeldMethodExpression.java:50)
at org.jboss.weld.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:40)
at org.jboss.weld.el.WeldMethodExpression.invoke(WeldMethodExpression.java:50)
at javax.faces.event.MethodExpressionActionListener.processAction(MethodExpressionActionListener.java:149)
at javax.faces.event.ActionEvent.processListener(ActionEvent.java:88)
at javax.faces.component.UIComponentBase.broadcast(UIComponentBase.java:814)
at javax.faces.component.UICommand.broadcast(UICommand.java:300)
at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:790)
at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1282)
at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:658)
at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:86)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:130)
at org.primefaces.webapp.filter.FileUploadFilter.doFilter(FileUploadFilter.java:78)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:132)
at io.undertow.websockets.jsr.JsrWebSocketFilter.doFilter(JsrWebSocketFilter.java:151)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:132)
at org.omnifaces.facesviews.FacesViewsForwardingFilter.filterExtensionLess(FacesViewsForwardingFilter.java:128)
at org.omnifaces.facesviews.FacesViewsForwardingFilter.doFilter(FacesViewsForwardingFilter.java:89)
at org.omnifaces.filter.HttpFilter.doFilter(HttpFilter.java:108)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:132)
at filter.LoginNocacheFilter.doFilter(LoginNocacheFilter.java:32)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:132)
at org.omnifaces.filter.CharacterEncodingFilter.doFilter(CharacterEncodingFilter.java:122)
at org.omnifaces.filter.HttpFilter.doFilter(HttpFilter.java:108)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:132)
at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:85)
at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:131)
at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.security.handlers.AuthenticationConstraintHandler.handleRequest(AuthenticationConstraintHandler.java:51)
at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
at io.undertow.servlet.handlers.security.ServletSecurityConstraintHandler.handleRequest(ServletSecurityConstraintHandler.java:56)
at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:58)
at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:72)
at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
at io.undertow.security.handlers.SecurityInitialHandler.handleRequest(SecurityInitialHandler.java:76)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:282)
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:261)
at io.undertow.servlet.handlers.ServletInitialHandler.access[=14=]0(ServletInitialHandler.java:80)
at io.undertow.servlet.handlers.ServletInitialHandler.handleRequest(ServletInitialHandler.java:172)
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:199)
at io.undertow.server.HttpServerExchange.run(HttpServerExchange.java:774)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.RuntimeException: javax.jms.JMSSecurityRuntimeException: HQ119032: User: null doesnt have permission=SEND on address {2}
at io.undertow.servlet.spec.RequestDispatcherImpl.forwardImpl(RequestDispatcherImpl.java:219)
at io.undertow.servlet.spec.RequestDispatcherImpl.forward(RequestDispatcherImpl.java:108)
at com.sun.faces.context.ExternalContextImpl.dispatch(ExternalContextImpl.java:643)
at admin.bean.SignInCheck.signIn(SignInCheck.java:63)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.sun.el.parser.AstValue.invoke(AstValue.java:292)
... 64 more
Caused by: javax.jms.JMSSecurityRuntimeException: HQ119032: User: null doesnt have permission=SEND on address {2}
at org.hornetq.jms.client.JmsExceptionUtils.convertToRuntimeException(JmsExceptionUtils.java:76)
at org.hornetq.jms.client.HornetQJMSProducer.send(HornetQJMSProducer.java:112)
at org.hornetq.jms.client.HornetQJMSProducer.send(HornetQJMSProducer.java:135)
at filter.SecurityCheck.sendMessageToDestination(SecurityCheck.java:54)
at filter.SecurityCheck.doAfterProcessing(SecurityCheck.java:107)
at filter.SecurityCheck.doFilter(SecurityCheck.java:161)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:132)
at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:85)
at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:263)
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchToPath(ServletInitialHandler.java:198)
at io.undertow.servlet.spec.RequestDispatcherImpl.forwardImpl(RequestDispatcherImpl.java:195)
... 72 more
Caused by: javax.jms.JMSSecurityException: HQ119032: User: null doesnt have permission=SEND on address {2}
at org.hornetq.core.protocol.core.impl.ChannelImpl.sendBlocking(ChannelImpl.java:399)
at org.hornetq.core.client.impl.ClientProducerImpl.sendRegularMessage(ClientProducerImpl.java:334)
at org.hornetq.core.client.impl.ClientProducerImpl.doSend(ClientProducerImpl.java:304)
at org.hornetq.core.client.impl.ClientProducerImpl.send(ClientProducerImpl.java:135)
at org.hornetq.jms.client.HornetQMessageProducer.doSendx(HornetQMessageProducer.java:524)
at org.hornetq.jms.client.HornetQMessageProducer.send(HornetQMessageProducer.java:210)
at org.hornetq.jms.client.HornetQMessageProducer.send(HornetQMessageProducer.java:200)
at org.hornetq.jms.client.HornetQJMSProducer.send(HornetQJMSProducer.java:107)
... 87 more
Caused by: HornetQSecurityException[errorType=SECURITY_EXCEPTION message=HQ119032: User: null doesnt have permission=SEND on address {2}]
... 95 more
当 <security-enabled>
被赋予 false
值时,消息通过定义的队列发送(由消息驱动 Bean (MDB) 接收)。但是,我只需要具有预定义 authority/role(ROLE_ADMIN
或 ROLE_USER
)的用户来创建队列并发送消息。
如上所示使用 <security-domain>
的方法失败并出现上述异常。
我尝试在 /standalone/configuration/application-roles.properties
中添加角色,完全按照
中使用的 ProjectRealm.properties
文件中的定义
<module-option name="rolesProperties"
value="file:${jboss.server.config.dir}/ProjectRealm.properties"/>
里面 <login-module>
但它也没有帮助。
admins=ROLE_ADMIN
users=ROLE_USER
在跨队列发送消息之前,还需要做什么来对用户进行身份验证?
补充:
JAAS 安全管理器使用以下域对使用 JDBC 领域(XA 数据源)的用户进行身份验证和授权。这已经很好用了。
<security-domain name="ProjectRealm" cache-type="default">
<authentication>
<login-module code="Database" flag="required">
<module-option name="dsJndiName" value="java:jboss/datasources/projectXADatasource"/>
<module-option name="principalsQuery" value="SELECT password FROM user_table WHERE email_id=?"/>
<module-option name="rolesQuery" value="SELECT user_role, 'Roles' FROM user_roles ur INNER JOIN user_table ut ON ur.user_id=ut.user_id WHERE ut.email_id=?"/>
<module-option name="hashAlgorithm" value="SHA-256"/>
<module-option name="hashEncoding" value="hex"/>
<module-option name="hashCharset" value="UTF-8"/>
<module-option name="hashStorePassword" value="false"/>
<module-option name="unauthenticatedIdentity" value="guest"/>
</login-module>
<login-module code="RoleMapping" flag="required">
<module-option name="rolesProperties" value="file:${jboss.server.config.dir}/ProjectRealm.properties"/>
<module-option name="replaceRole" value="false"/>
</login-module>
</authentication>
</security-domain>
队列被注入到认证 Servlet 过滤器中,JMSContext
使用该过滤器在用户成功认证和授权后通过队列发送消息。
@WebFilter(filterName = "SecurityCheck", urlPatterns = {"/WEB-INF/jaas/*"}, dispatcherTypes = {DispatcherType.FORWARD})
public final class SecurityCheck implements Filter {
@Resource(lookup = "java:/jms/destination")
private Queue queue;
@Inject
@JMSConnectionFactory("java:jboss/exported/jms/destinationFactory")
private JMSContext context;
// jms/destinationFactory is expected to work here but it only works using the fully qualified namespace as above.
public SecurityCheck() {}
private void sendMessageToDestination(String message) throws JMSException {
context.createProducer().send(queue, message);
}
private void doBeforeProcessing(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
String userName = request.getParameter("userName");
request.login(userName.trim(), request.getParameter("password"));
}
private void doAfterProcessing(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException, JMSException {
if (request.isUserInRole("ROLE_ADMIN")) {
sendMessageToDestination("Message");
// Redirect to a secure area.
} else if (request.isUserInRole("ROLE_USER")) {
sendMessageToDestination("Message");
// Redirect to a secure area.
}
//...
}
//...
}
我将自签名 SSL 证书用于纯粹的测试目的。因此,它使用 https://localhost:8443/ContextPath
访问受保护的 Web 资源
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
在 web.xml
.
更新:
消息驱动 Bean 消费消息:
@JMSDestinationDefinition(name = "destination", interfaceName = "javax.jms.Queue", resourceAdapter = "jmsra", destinationName = "destination")
@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = "jms/destination"),
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
@ActivationConfigProperty(propertyName = "connectionFactoryLookup", propertyValue = "java:jboss/exported/jms/destinationFactory"),
@ActivationConfigProperty(propertyName = "messagingType", propertyValue = "javax.jms.MessageListener"),
@ActivationConfigProperty(propertyName = "destination", propertyValue = "java:/jms/destination"),
@ActivationConfigProperty(propertyName = "useJNDI", propertyValue = "true")
})
public class UserStatusMessageBean implements MessageListener {
public UserStatusMessageBean() {}
@Resource
private MessageDrivenContext messageDrivenContext;
@EJB
private UserStatusService userStatusService;
@Override
public void onMessage(Message message) {
try {
if (message instanceof TextMessage) {
TextMessage textMessage = (TextMessage) message;
String text = textMessage.getText();
if (StringUtils.isNotBlank(text)) {
userStatusService.addHost(text);
} else {
System.out.println("No message found.");
}
} else {
System.out.println("Message is of wrong type : " + message.getClass().getName());
}
} catch (JMSException e) {
messageDrivenContext.setRollbackOnly();
System.out.println(e);
} catch (Throwable e) {
System.out.println(e);
}
}
}
有一个远程 EJB 被注入到上面的 MDB 中,它需要定义的权限。
@Stateless
@DeclareRoles(value = {"ROLE_ADMIN", "ROLE_USER"})
@RolesAllowed(value = {"ROLE_ADMIN", "ROLE_USER"})
public class UserStatusBean implements UserStatusService {
@PersistenceContext
private EntityManager entityManager;
@Override
public void addHost(String hostName) {
// Insert or update via JPA.
}
}
部署应用程序时,服务器会递归地抛出以下异常,除非在
中给出 false
值
<security-enabled>false</security-enabled>
20:21:55,343 ERROR [org.hornetq.ra] (default-threads - 3) HQ154003: Unable to reconnect org.hornetq.ra.inflow.HornetQActivationSpec(ra=org.hornetq.ra.HornetQResourceAdapter@dc9e56 destination=java:/jms/destination destinationType=javax.jms.Queue ack=Auto-acknowledge durable=false clientID=null user=null maxSession=15): HornetQSecurityException[errorType=SECURITY_EXCEPTION message=HQ119032: User: null doesnt have permission=CONSUME on address {2}]
at org.hornetq.core.protocol.core.impl.ChannelImpl.sendBlocking(ChannelImpl.java:399)
at org.hornetq.core.client.impl.ClientSessionImpl.internalCreateConsumer(ClientSessionImpl.java:2064)
at org.hornetq.core.client.impl.ClientSessionImpl.createConsumer(ClientSessionImpl.java:527)
at org.hornetq.core.client.impl.ClientSessionImpl.createConsumer(ClientSessionImpl.java:474)
at org.hornetq.core.client.impl.DelegatingSession.createConsumer(DelegatingSession.java:206)
at org.hornetq.ra.inflow.HornetQMessageHandler.setup(HornetQMessageHandler.java:184)
at org.hornetq.ra.inflow.HornetQActivation.setup(HornetQActivation.java:340)
at org.hornetq.ra.inflow.HornetQActivation.handleFailure(HornetQActivation.java:768)
at org.hornetq.ra.inflow.HornetQActivation$SetupActivation.run(HornetQActivation.java:823)
at org.jboss.jca.core.workmanager.WorkWrapper.run(WorkWrapper.java:226)
at org.jboss.threads.SimpleDirectExecutor.execute(SimpleDirectExecutor.java:33)
at org.jboss.threads.QueueExecutor.runTask(QueueExecutor.java:808)
at org.jboss.threads.QueueExecutor.access0(QueueExecutor.java:45)
at org.jboss.threads.QueueExecutor$Worker.run(QueueExecutor.java:828)
at java.lang.Thread.run(Thread.java:745)
at org.jboss.threads.JBossThread.run(JBossThread.java:320)
我在 WildFly 9.0.2 上重现了同样的问题,(使用 REST EJB 资源而不是您的 Servlet)
23:31:22,138 ERROR [io.undertow.request] (default task-7) UT005023: Exception handling request to /jeeshop-admin/rs/users/administrators: org.jboss.resteasy.spi.UnhandledException: javax.jms.JMSSecurityException: HQ119032: User: null doesnt have permission=SEND on address {2}
at org.jboss.resteasy.core.ExceptionHandler.handleApplicationException(ExceptionHandler.java:76)
为了修复它,我做了以下操作:
@Resource(mappedName = "java:jboss/exported/jms/destinationFactory")
ConnectionFactory factory;
private void sendMessageToDestination(String message, String user) throws JMSException {
try (Connection connection = factory.createConnection(user,"hardcodedPassword");
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer producer = session.createProducer(queue)) {
TextMessage textMessage = session.createTextMessage(message);
producer.send(textMessage);
}
}
如您所见,我在创建连接期间提供了有效的用户名和密码。此用户与 hornetq-server 安全设置中配置的角色相同。
当时我没有使用与您完全相同的安全域(我使用我自己的代码来重现您的问题)。
如果你的效果不佳,请看这里:
<security-domain name="jeeshop" cache-type="default">
<authentication>
<login-module code="Database" flag="required">
<module-option name="dsJndiName" value="java:/JeeshopDS"/>
<module-option name="principalsQuery" value="select password from User where login = ? and (disabled is null or disabled = 0) and activated = 1"/>
<module-option name="rolesQuery" value="select name,'Roles' from Role r, User_Role ur, User u where u.login=? and u.id = ur.userId and r.id = ur.roleId"/>
<module-option name="hashAlgorithm" value="SHA-256"/>
<module-option name="hashEncoding" value="base64"/>
<module-option name="unauthenticatedIdentity" value="guest"/>
</login-module>
</authentication>
</security-domain>
我的数据源:
<xa-datasource jndi-name="java:/JeeshopDS" pool-name="JeeshopDS" enabled="true">
<xa-datasource-property name="ServerName">
localhost
</xa-datasource-property>
<xa-datasource-property name="DatabaseName">
jeeshop
</xa-datasource-property>
<driver>mysql</driver>
<security>
<user-name>jeeshop</user-name>
<password>test</password>
</security>
<validation>
<valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLValidConnectionChecker"/>
<exception-sorter class-name="org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLExceptionSorter"/>
</validation>
</xa-datasource>
我的角色存储 DDL 提取:
CREATE TABLE IF NOT EXISTS Role (
id bigint(20) NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY UK_Role_name (name)
);
CREATE TABLE IF NOT EXISTS User_Role (
userId bigint(20) NOT NULL,
roleId bigint(20) NOT NULL,
PRIMARY KEY (userId,roleId)
);
编辑
以下 MDB 允许读取 sendMessageToDestination()
生成消息的目标:
@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
@ActivationConfigProperty(propertyName = "useJNDI", propertyValue = "true"),
@ActivationConfigProperty(propertyName = "destination", propertyValue = "java:jboss/exported/jms/destination"),
@ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge")})
public class TestMDB implements MessageListener {
@Override
@PermitAll
public void onMessage(Message message) {
if (message instanceof TextMessage) {
try {
System.out.println(((TextMessage) message).getText());
} catch (JMSException e) {
// propagate for transaction rollback
throw new IllegalArgumentException(e);
}
}
}
}
您最终可以更改 MDB 使用的主体。请参阅这些链接:
使用WildFly 9.0.2 final,<hornetq-server>
部分在standalone-full.xml
中定义如下。
<address-settings>
、<acceptors>
和 <connectors>
等部分完全省略,因为我没有更改其中的任何内容。
<hornetq-server>
<security-domain>ProjectRealm</security-domain>
<security-enabled>true</security-enabled>
<journal-file-size>102400</journal-file-size>
<security-settings>
<security-setting match="#">
<permission type="send" roles="ROLE_USER ROLE_ADMIN"/>
<permission type="consume" roles="ROLE_USER ROLE_ADMIN"/>
<permission type="createDurableQueue" roles="ROLE_USER ROLE_ADMIN"/>
<permission type="deleteDurableQueue" roles="ROLE_USER ROLE_ADMIN"/>
<permission type="createNonDurableQueue" roles="ROLE_USER ROLE_ADMIN"/>
<permission type="deleteNonDurableQueue" roles="ROLE_USER ROLE_ADMIN"/>
</security-setting>
</security-settings>
<jms-connection-factories>
<connection-factory name="destinationFactory">
<connectors>
<connector-ref connector-name="http-connector"/>
</connectors>
<entries>
<entry name="java:jboss/exported/jms/destinationFactory"/>
</entries>
</connection-factory>
</jms-connection-factories>
<jms-destinations>
<jms-queue name="userStatusQueue">
<entry name="jms/destination"/>
<entry name="java:jboss/exported/jms/destination"/>
</jms-queue>
</jms-destinations>
</hornetq-server>
它定义了一个名为 destinationFactory
的连接工厂,它使用 http-connector
和一个名为 userStatusQueue
的队列,它们绑定到嵌套的 <entry>
元素中列出的 JNDI 名称.
它还定义了一个安全域。
<security-domain>ProjectRealm</security-domain>
使用
启用安全性(默认)<security-enabled>true</security-enabled>
在这种情况下,它会导致抛出以下异常。
15:49:28,093 WARNING [javax.enterprise.resource.webcontainer.jsf.lifecycle] (default task-2) java.lang.RuntimeException: javax.jms.JMSSecurityRuntimeException: HQ119032: User: null doesnt have permission=SEND on address {2}: javax.el.ELException: java.lang.RuntimeException: javax.jms.JMSSecurityRuntimeException: HQ119032: User: null doesnt have permission=SEND on address {2}
at com.sun.el.parser.AstValue.invoke(AstValue.java:296)
at com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:304)
at org.jboss.weld.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:40)
at org.jboss.weld.el.WeldMethodExpression.invoke(WeldMethodExpression.java:50)
at org.jboss.weld.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:40)
at org.jboss.weld.el.WeldMethodExpression.invoke(WeldMethodExpression.java:50)
at javax.faces.event.MethodExpressionActionListener.processAction(MethodExpressionActionListener.java:149)
at javax.faces.event.ActionEvent.processListener(ActionEvent.java:88)
at javax.faces.component.UIComponentBase.broadcast(UIComponentBase.java:814)
at javax.faces.component.UICommand.broadcast(UICommand.java:300)
at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:790)
at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1282)
at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:658)
at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:86)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:130)
at org.primefaces.webapp.filter.FileUploadFilter.doFilter(FileUploadFilter.java:78)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:132)
at io.undertow.websockets.jsr.JsrWebSocketFilter.doFilter(JsrWebSocketFilter.java:151)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:132)
at org.omnifaces.facesviews.FacesViewsForwardingFilter.filterExtensionLess(FacesViewsForwardingFilter.java:128)
at org.omnifaces.facesviews.FacesViewsForwardingFilter.doFilter(FacesViewsForwardingFilter.java:89)
at org.omnifaces.filter.HttpFilter.doFilter(HttpFilter.java:108)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:132)
at filter.LoginNocacheFilter.doFilter(LoginNocacheFilter.java:32)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:132)
at org.omnifaces.filter.CharacterEncodingFilter.doFilter(CharacterEncodingFilter.java:122)
at org.omnifaces.filter.HttpFilter.doFilter(HttpFilter.java:108)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:132)
at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:85)
at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:131)
at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.security.handlers.AuthenticationConstraintHandler.handleRequest(AuthenticationConstraintHandler.java:51)
at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
at io.undertow.servlet.handlers.security.ServletSecurityConstraintHandler.handleRequest(ServletSecurityConstraintHandler.java:56)
at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:58)
at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:72)
at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
at io.undertow.security.handlers.SecurityInitialHandler.handleRequest(SecurityInitialHandler.java:76)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:282)
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:261)
at io.undertow.servlet.handlers.ServletInitialHandler.access[=14=]0(ServletInitialHandler.java:80)
at io.undertow.servlet.handlers.ServletInitialHandler.handleRequest(ServletInitialHandler.java:172)
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:199)
at io.undertow.server.HttpServerExchange.run(HttpServerExchange.java:774)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.RuntimeException: javax.jms.JMSSecurityRuntimeException: HQ119032: User: null doesnt have permission=SEND on address {2}
at io.undertow.servlet.spec.RequestDispatcherImpl.forwardImpl(RequestDispatcherImpl.java:219)
at io.undertow.servlet.spec.RequestDispatcherImpl.forward(RequestDispatcherImpl.java:108)
at com.sun.faces.context.ExternalContextImpl.dispatch(ExternalContextImpl.java:643)
at admin.bean.SignInCheck.signIn(SignInCheck.java:63)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.sun.el.parser.AstValue.invoke(AstValue.java:292)
... 64 more
Caused by: javax.jms.JMSSecurityRuntimeException: HQ119032: User: null doesnt have permission=SEND on address {2}
at org.hornetq.jms.client.JmsExceptionUtils.convertToRuntimeException(JmsExceptionUtils.java:76)
at org.hornetq.jms.client.HornetQJMSProducer.send(HornetQJMSProducer.java:112)
at org.hornetq.jms.client.HornetQJMSProducer.send(HornetQJMSProducer.java:135)
at filter.SecurityCheck.sendMessageToDestination(SecurityCheck.java:54)
at filter.SecurityCheck.doAfterProcessing(SecurityCheck.java:107)
at filter.SecurityCheck.doFilter(SecurityCheck.java:161)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:132)
at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:85)
at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:263)
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchToPath(ServletInitialHandler.java:198)
at io.undertow.servlet.spec.RequestDispatcherImpl.forwardImpl(RequestDispatcherImpl.java:195)
... 72 more
Caused by: javax.jms.JMSSecurityException: HQ119032: User: null doesnt have permission=SEND on address {2}
at org.hornetq.core.protocol.core.impl.ChannelImpl.sendBlocking(ChannelImpl.java:399)
at org.hornetq.core.client.impl.ClientProducerImpl.sendRegularMessage(ClientProducerImpl.java:334)
at org.hornetq.core.client.impl.ClientProducerImpl.doSend(ClientProducerImpl.java:304)
at org.hornetq.core.client.impl.ClientProducerImpl.send(ClientProducerImpl.java:135)
at org.hornetq.jms.client.HornetQMessageProducer.doSendx(HornetQMessageProducer.java:524)
at org.hornetq.jms.client.HornetQMessageProducer.send(HornetQMessageProducer.java:210)
at org.hornetq.jms.client.HornetQMessageProducer.send(HornetQMessageProducer.java:200)
at org.hornetq.jms.client.HornetQJMSProducer.send(HornetQJMSProducer.java:107)
... 87 more
Caused by: HornetQSecurityException[errorType=SECURITY_EXCEPTION message=HQ119032: User: null doesnt have permission=SEND on address {2}]
... 95 more
当 <security-enabled>
被赋予 false
值时,消息通过定义的队列发送(由消息驱动 Bean (MDB) 接收)。但是,我只需要具有预定义 authority/role(ROLE_ADMIN
或 ROLE_USER
)的用户来创建队列并发送消息。
如上所示使用 <security-domain>
的方法失败并出现上述异常。
我尝试在 /standalone/configuration/application-roles.properties
中添加角色,完全按照
ProjectRealm.properties
文件中的定义
<module-option name="rolesProperties"
value="file:${jboss.server.config.dir}/ProjectRealm.properties"/>
里面 <login-module>
但它也没有帮助。
admins=ROLE_ADMIN
users=ROLE_USER
在跨队列发送消息之前,还需要做什么来对用户进行身份验证?
补充:
JAAS 安全管理器使用以下域对使用 JDBC 领域(XA 数据源)的用户进行身份验证和授权。这已经很好用了。
<security-domain name="ProjectRealm" cache-type="default">
<authentication>
<login-module code="Database" flag="required">
<module-option name="dsJndiName" value="java:jboss/datasources/projectXADatasource"/>
<module-option name="principalsQuery" value="SELECT password FROM user_table WHERE email_id=?"/>
<module-option name="rolesQuery" value="SELECT user_role, 'Roles' FROM user_roles ur INNER JOIN user_table ut ON ur.user_id=ut.user_id WHERE ut.email_id=?"/>
<module-option name="hashAlgorithm" value="SHA-256"/>
<module-option name="hashEncoding" value="hex"/>
<module-option name="hashCharset" value="UTF-8"/>
<module-option name="hashStorePassword" value="false"/>
<module-option name="unauthenticatedIdentity" value="guest"/>
</login-module>
<login-module code="RoleMapping" flag="required">
<module-option name="rolesProperties" value="file:${jboss.server.config.dir}/ProjectRealm.properties"/>
<module-option name="replaceRole" value="false"/>
</login-module>
</authentication>
</security-domain>
队列被注入到认证 Servlet 过滤器中,JMSContext
使用该过滤器在用户成功认证和授权后通过队列发送消息。
@WebFilter(filterName = "SecurityCheck", urlPatterns = {"/WEB-INF/jaas/*"}, dispatcherTypes = {DispatcherType.FORWARD})
public final class SecurityCheck implements Filter {
@Resource(lookup = "java:/jms/destination")
private Queue queue;
@Inject
@JMSConnectionFactory("java:jboss/exported/jms/destinationFactory")
private JMSContext context;
// jms/destinationFactory is expected to work here but it only works using the fully qualified namespace as above.
public SecurityCheck() {}
private void sendMessageToDestination(String message) throws JMSException {
context.createProducer().send(queue, message);
}
private void doBeforeProcessing(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
String userName = request.getParameter("userName");
request.login(userName.trim(), request.getParameter("password"));
}
private void doAfterProcessing(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException, JMSException {
if (request.isUserInRole("ROLE_ADMIN")) {
sendMessageToDestination("Message");
// Redirect to a secure area.
} else if (request.isUserInRole("ROLE_USER")) {
sendMessageToDestination("Message");
// Redirect to a secure area.
}
//...
}
//...
}
我将自签名 SSL 证书用于纯粹的测试目的。因此,它使用 https://localhost:8443/ContextPath
访问受保护的 Web 资源
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
在 web.xml
.
更新:
消息驱动 Bean 消费消息:
@JMSDestinationDefinition(name = "destination", interfaceName = "javax.jms.Queue", resourceAdapter = "jmsra", destinationName = "destination")
@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = "jms/destination"),
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
@ActivationConfigProperty(propertyName = "connectionFactoryLookup", propertyValue = "java:jboss/exported/jms/destinationFactory"),
@ActivationConfigProperty(propertyName = "messagingType", propertyValue = "javax.jms.MessageListener"),
@ActivationConfigProperty(propertyName = "destination", propertyValue = "java:/jms/destination"),
@ActivationConfigProperty(propertyName = "useJNDI", propertyValue = "true")
})
public class UserStatusMessageBean implements MessageListener {
public UserStatusMessageBean() {}
@Resource
private MessageDrivenContext messageDrivenContext;
@EJB
private UserStatusService userStatusService;
@Override
public void onMessage(Message message) {
try {
if (message instanceof TextMessage) {
TextMessage textMessage = (TextMessage) message;
String text = textMessage.getText();
if (StringUtils.isNotBlank(text)) {
userStatusService.addHost(text);
} else {
System.out.println("No message found.");
}
} else {
System.out.println("Message is of wrong type : " + message.getClass().getName());
}
} catch (JMSException e) {
messageDrivenContext.setRollbackOnly();
System.out.println(e);
} catch (Throwable e) {
System.out.println(e);
}
}
}
有一个远程 EJB 被注入到上面的 MDB 中,它需要定义的权限。
@Stateless
@DeclareRoles(value = {"ROLE_ADMIN", "ROLE_USER"})
@RolesAllowed(value = {"ROLE_ADMIN", "ROLE_USER"})
public class UserStatusBean implements UserStatusService {
@PersistenceContext
private EntityManager entityManager;
@Override
public void addHost(String hostName) {
// Insert or update via JPA.
}
}
部署应用程序时,服务器会递归地抛出以下异常,除非在
中给出false
值
<security-enabled>false</security-enabled>
20:21:55,343 ERROR [org.hornetq.ra] (default-threads - 3) HQ154003: Unable to reconnect org.hornetq.ra.inflow.HornetQActivationSpec(ra=org.hornetq.ra.HornetQResourceAdapter@dc9e56 destination=java:/jms/destination destinationType=javax.jms.Queue ack=Auto-acknowledge durable=false clientID=null user=null maxSession=15): HornetQSecurityException[errorType=SECURITY_EXCEPTION message=HQ119032: User: null doesnt have permission=CONSUME on address {2}]
at org.hornetq.core.protocol.core.impl.ChannelImpl.sendBlocking(ChannelImpl.java:399)
at org.hornetq.core.client.impl.ClientSessionImpl.internalCreateConsumer(ClientSessionImpl.java:2064)
at org.hornetq.core.client.impl.ClientSessionImpl.createConsumer(ClientSessionImpl.java:527)
at org.hornetq.core.client.impl.ClientSessionImpl.createConsumer(ClientSessionImpl.java:474)
at org.hornetq.core.client.impl.DelegatingSession.createConsumer(DelegatingSession.java:206)
at org.hornetq.ra.inflow.HornetQMessageHandler.setup(HornetQMessageHandler.java:184)
at org.hornetq.ra.inflow.HornetQActivation.setup(HornetQActivation.java:340)
at org.hornetq.ra.inflow.HornetQActivation.handleFailure(HornetQActivation.java:768)
at org.hornetq.ra.inflow.HornetQActivation$SetupActivation.run(HornetQActivation.java:823)
at org.jboss.jca.core.workmanager.WorkWrapper.run(WorkWrapper.java:226)
at org.jboss.threads.SimpleDirectExecutor.execute(SimpleDirectExecutor.java:33)
at org.jboss.threads.QueueExecutor.runTask(QueueExecutor.java:808)
at org.jboss.threads.QueueExecutor.access0(QueueExecutor.java:45)
at org.jboss.threads.QueueExecutor$Worker.run(QueueExecutor.java:828)
at java.lang.Thread.run(Thread.java:745)
at org.jboss.threads.JBossThread.run(JBossThread.java:320)
我在 WildFly 9.0.2 上重现了同样的问题,(使用 REST EJB 资源而不是您的 Servlet)
23:31:22,138 ERROR [io.undertow.request] (default task-7) UT005023: Exception handling request to /jeeshop-admin/rs/users/administrators: org.jboss.resteasy.spi.UnhandledException: javax.jms.JMSSecurityException: HQ119032: User: null doesnt have permission=SEND on address {2}
at org.jboss.resteasy.core.ExceptionHandler.handleApplicationException(ExceptionHandler.java:76)
为了修复它,我做了以下操作:
@Resource(mappedName = "java:jboss/exported/jms/destinationFactory")
ConnectionFactory factory;
private void sendMessageToDestination(String message, String user) throws JMSException {
try (Connection connection = factory.createConnection(user,"hardcodedPassword");
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer producer = session.createProducer(queue)) {
TextMessage textMessage = session.createTextMessage(message);
producer.send(textMessage);
}
}
如您所见,我在创建连接期间提供了有效的用户名和密码。此用户与 hornetq-server 安全设置中配置的角色相同。
当时我没有使用与您完全相同的安全域(我使用我自己的代码来重现您的问题)。 如果你的效果不佳,请看这里:
<security-domain name="jeeshop" cache-type="default">
<authentication>
<login-module code="Database" flag="required">
<module-option name="dsJndiName" value="java:/JeeshopDS"/>
<module-option name="principalsQuery" value="select password from User where login = ? and (disabled is null or disabled = 0) and activated = 1"/>
<module-option name="rolesQuery" value="select name,'Roles' from Role r, User_Role ur, User u where u.login=? and u.id = ur.userId and r.id = ur.roleId"/>
<module-option name="hashAlgorithm" value="SHA-256"/>
<module-option name="hashEncoding" value="base64"/>
<module-option name="unauthenticatedIdentity" value="guest"/>
</login-module>
</authentication>
</security-domain>
我的数据源:
<xa-datasource jndi-name="java:/JeeshopDS" pool-name="JeeshopDS" enabled="true">
<xa-datasource-property name="ServerName">
localhost
</xa-datasource-property>
<xa-datasource-property name="DatabaseName">
jeeshop
</xa-datasource-property>
<driver>mysql</driver>
<security>
<user-name>jeeshop</user-name>
<password>test</password>
</security>
<validation>
<valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLValidConnectionChecker"/>
<exception-sorter class-name="org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLExceptionSorter"/>
</validation>
</xa-datasource>
我的角色存储 DDL 提取:
CREATE TABLE IF NOT EXISTS Role (
id bigint(20) NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY UK_Role_name (name)
);
CREATE TABLE IF NOT EXISTS User_Role (
userId bigint(20) NOT NULL,
roleId bigint(20) NOT NULL,
PRIMARY KEY (userId,roleId)
);
编辑
以下 MDB 允许读取 sendMessageToDestination()
生成消息的目标:
@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
@ActivationConfigProperty(propertyName = "useJNDI", propertyValue = "true"),
@ActivationConfigProperty(propertyName = "destination", propertyValue = "java:jboss/exported/jms/destination"),
@ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge")})
public class TestMDB implements MessageListener {
@Override
@PermitAll
public void onMessage(Message message) {
if (message instanceof TextMessage) {
try {
System.out.println(((TextMessage) message).getText());
} catch (JMSException e) {
// propagate for transaction rollback
throw new IllegalArgumentException(e);
}
}
}
}
您最终可以更改 MDB 使用的主体。请参阅这些链接: