当前位置: 首页 > ActiveMQ in Action 读书笔记 > 正文

6.2 activeMQ 授权 Authorization

 6.2 Authorization

To build upon authentication, consider a use case requiring more fine-grained controlover clients to authorize certain tasks. In most stock trading applications, only specificapplications can write to a given destination. After all, you wouldn’t want any oldapplication publishing stock prices to the STOCKS.* destinations. Only an authenticatedand authorized application should have this ability.

For this reason, ActiveMQ provides two levels of authorization: operation-level authorization and message-level authorization. These two types of authorization provide a more detailed level of control than simple authentication. This section discusses these two types of authorization and walks through some examples to demonstrate each.

 6.2 activeMQ 授权

创建完验证后,考虑下面这种情况:需要对客户端进行更细粒度的控制以控制对特定任务的授权.在大多数股票交易程序中,只有特定的应用程序可以往给定的目的地写入数据.毕竟,你不希望任何老程序还能往STOCKS.*消息目的地发布股票价格信息,只有验证和授权过后的程序才可以具有发布股票消息到目的地的功能.

为此,ActiveMQ提供两种级别的授权:操作级别授权和消息级别授权.这两者授权方式提供了 比简单认证方式更细致的访问控制.本节将讨论这两种授权方式并通过实例加以说明.

 6.2.1 Destination-level authorization

There are three types of user-level operations with JMS destinations:
 Read—The ability to receive messages from the destination
 Write—The ability to send messages to the destination
 Admin—The ability to administer the destination

 6.2.1 目的地级别的授权

针对JMS消息目的地一共有三种用户操作权限:
读 — 具有从特定目的地接收消息的权限
写 — 具有发送消息到特定目的地的权限
管理 — 具有管理消息目的地的权限

 Through these well-known operations, you can control the ability to perform theoperations. Using the ActiveMQ XML configuration file, such authorization can beeasily defined. Take a look at the following listing to add some operation-specificauthorization to some destinations.  你可以控制上述三种常用的操作.使用ActiveMQ的XML配置文件可以很容易的配置上面的授权方式.下面的实例代码为一些消息目的地添加了几种特殊的操作授权:
 Listing 6.2 Configuring destination-level authorization

...
<plugins>
  <jaasAuthenticationPlugin configuration="activemq-domain" />
  <authorizationPlugin>
    <map>
      <authorizationMap>
        <authorizationEntries>
          <authorizationEntry topic=">" read="admins" write="admins" admin="admins" />
          <authorizationEntry topic="STOCKS.>" read="consumers" write="publishers" admin="publishers" />
          <authorizationEntry topic="STOCKS.ORCL" read="guests" />
          <authorizationEntry topic="ActiveMQ.Advisory.>" 
                              read="admins,publishers,consumers,guests" 
                              write="admins,publishers,consumers,guests" 
                              admin="admins,publishers,consumers,guests" />
        </authorizationEntries>
      </authorizationMap>
    </map>
  </authorizationPlugin>
</plugins>
...
 In the listing, the JAAS authorization plug-in has been defined and pointed at theactivemq-domain configuration in the login.config file. It has also been provided witha map of authorization entries. When configuring the map of authorization entries,the first task is to define the destination to be secured. This is achieved through theuse of either a topic or a queue attribute on the entry. The next task is to declarewhich users and/or groups have privileges for operations on that destination.  在上面的代码清单配置了JAAS授权插件并指向login.config文件中名称为activemq-domain的配置.并且,该配置还提供了一个包含一系列的授权实体的授权映射.在配置授权实体映射时,首要的工作是定义受安全保护的消息目的地.可以使用authorizationEntry的topic或者queue来定义受安全保护的消息目的地名称,接下来是要配置哪个用户和/或群组具有操作这个消息目的地的权限.
 A handy feature is the ability to define the destination value using wildcards. Forexample, STOCKS.> means the entry applies to all destinations in the STOCKS pathrecursively. You can find more information on wildcards in chapter 11. Also, theauthorization operations will accept either a single group or a comma-separated list ofgroups as a value.

Considering this explanation, the configuration used in the previous example can be translated as follows:

Users from the admins group have full access to all topicsConsumers can consume and publishers can publish to the destinations in the STOCKS path

Guests can only consume from the STOCKS.ORCL topic

 在配置消息目的地时,可以使用通配符来简化配置.例如,”STOCKS.>” 表示该授权实体可以递归地应用到路径以STOCKS开头的目的地中.更多有关于通配符的内容请参阅第11章内容.同时,配置中操作属性值可以是单一的群组名称或者一个以逗号分割的群组名称集合.

作为配置说明,上面的配置可以被翻译为:

来自admins群组中的用户具有所有主题的操作权限.

消息消费者可以消费路径以STOCKS开头的主题中的消息,消息发布者可以发布消息到路径以STOCKS开头的主题中.

guests群组中的用户只能消费STOCKS.ORCL主题中的消息.

 The previous example uses an additive model, where all operations on a topic have been restricted to administrators only. Beyond this, specific operations on specific destinations are added as needed.

In order to start the broker to test out both the JAAS authentication plug-in as well as the authorization entries, use the following command to start the broker:

 前面例子中的配置采用了一种特殊的模式使得所有的主题操作都受到管理员的约束.除此之外,还给特定的消息目的地配置了具体的操作权限.

为了测试配置了授权实体的JAAS插件,使用如下命令来启动代理:

  ${ACTIVEMQ_HOME}/bin/activemq console -Djava.security.auth.login.config=src/main/resources/org/apache/activemq/book/ch6/login.config xbean:src/main/resources/org/apache/activemq/book/ch6/activemq-authorization.xml
(window启动命令:%ACTIVEMQ_HOME%/bin/activemq -Djava.security.auth.login.config=src/main/resources/org/apache/activemq/book/ch6/login.config xbean:src/main/resources/org/apache/activemq/book/ch6/activemq-authorization.xml)

...
 
xbean:src/main/resources/org/apache/activemq/book/ch6/activemq-authorization.xml
INFO | PListStore:/Users/bsnyder/amq/apache-activemq-5.4.1/data/localhost/tmp_storage started
INFO | Using Persistence Adapter: KahaDBPersistenceAdapter[/Users/bsnyder/amq/apache-activemq-5.4.1/data/localhost/KahaDB]
INFO | JMX consoles can connect to service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi
INFO | ActiveMQ 5.4.1 JMS Message Broker (localhost) is starting
INFO | For help or more information please see:http://activemq.apache.org/
INFO | Scheduler using directory:/Users/bsnyder/amq/apache-activemq-5.4.1/data/localhost/scheduler
INFO | JobSchedulerStore:/Users/bsnyder/amq/apache-activemq-5.4.1/data/localhost/schedulerstarted
INFO | Listening for connections at: tcp://localhost:61616
INFO | Connector openwire Started
INFO | ActiveMQ JMS Message Broker
(localhost, ID:mongoose.local-62861-1289968271876-0:0) started
 Note the use of the java.security.auth.login.config system property to point tothe login.config file. This ensures that ActiveMQ can locate the file for its use.Now let’s see how introduction of authorization affects JMS clients. We’ll demonstrateour authorization setup by trying to consume from the stock topics. As we weredoing for the publisher example in the previous section, we’ll modify our originalstock portfolio consumer and make it pass an appropriate connection username andpassword. For example, in order to try consuming from the STOCKS.ORCL topic asguest, we should add the following to the consumer (marked as bold):  注意,使用java.security.auth.login.config系统属性是为了指到login.config文件,保证ActiveMQ能够定位并使用login.config文件.下面让我们看看引入的授权是如何影响客户端的.我们将通过消费股票消息来说明授权操作步骤.如前面章节中修改publisher一样,我们将修改原先的stock portfolio实例中consumer的代码以便能够传入适当的用户名和密码然后建立连接.比如,为了使得guest用户可以消费来自STOCKS.ORCL主题的消息,我们需要添加下面的代码到consumer(添加的代码以粗体显示)
  

... 
private String username = "guest";
private String password = "password";
public Consumer() throws JMSException 
{
  factory = new ActiveMQConnectionFactory(brokerURL);
  connection = factory.createConnection(username, password);
  connection.start();
  session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
}
...
 Credentials have been added so that the consumer can create a connection to the brokerusing an appropriate username and password. The modified consumer can befound in the org.apache.activemq.book.ch6.Consumer class. Now we can run ourexample and see how authorization configuration at the broker affects the client. Firststart the publisher using the following command:   授权凭证被加入到consumer的代码中,这样consumer可以使用适当的用户名了密码来建立到代理的连接.修改后的consumer参阅org.apache.activemq.book.ch6.Consumer类文件.现在,我们可以运行修改后的例子,以便观察代理中采用的授权配置如何影响客户端.首先,使用下面的命令启动publisher:
  

$ mvn exec:java -Dexec.mainClass=org.apache.activemq.book.ch6.Publisher -Dexec.args="CSCO ORCL"
 
...
Sending: {price=24.07337784180, stock=ORCL, offer=24.0974512196,up=true} on destination: topic://STOCKS.ORCL
Sending: {price=73.49647952723, stock=CSCO, offer=73.5699760067,up=false} on destination: topic://STOCKS.CSCO
Sending: {price=24.282731805343, stock=ORCL, offer=24.307014537149,up=true} on destination: topic://STOCKS.ORCL
Sending: {price=74.1916498091, stock=CSCO, offer=74.265841458,up=true} on destination: topic://STOCKS.CSCO
Sending: {price=24.350683304888, stock=ORCL, offer=24.375033988192,up=true} on destination: topic://STOCKS.ORCL
Sending: {price=24.46113711010, stock=ORCL, offer=24.485598247216,up=true} on destination: topic://STOCKS.ORCL
Sending: {price=24.219079287873, stock=ORCL, offer=24.243298367160,up=false} on destination: topic://STOCKS.ORCL
Sending: {price=24.282977831328, stock=ORCL, offer=24.307260809160,up=true} on destination: topic://STOCKS.ORCL
Sending: {price=24.33344653108, stock=ORCL, offer=24.35777997761,up=true} on destination: topic://STOCKS.ORCL
Sending: {price=73.86498266780, stock=CSCO, offer=73.93884765047,up=false} on destination: topic://STOCKS.CSCO
Published '10' of '10' price messages
...
 Now let’s see what happens when we try to access different destinations with guest usercredentials. For example, if you instruct it to consume messages from STOCKS.CSCOtopic, you’ll see the following exception:  接下来,让我们看看使用guest用来访问不同的消息目的地时会发生什么情况.比如,假如使用下面的命令,使用guest用户消费来自STOCKS.CSCO主题的消息,你将看到后面的异常:
  

$ mvn exec:java -Dexec.mainClass=org.apache.activemq.book.ch6.Consumer -Dexec.args="STOCKS.CSCO"
...
Exception in thread "main"
javax.jms.JMSException: User guest is not authorized to read from: topic://STOCKS.CSCO ...
 This is exactly what we expected to happen. Consuming from the STOCKS.CSCO topicis restricted due to the authorization settings in listing 6.2. But the authorization configurationdoes allow guests to consume from the STOCKS.ORCL topic as shown in thefollowing example:  这个与我们期望的相符合,因为在代码列表6.2中对消费STOCKS.CSCO主题中的消息消费者做了限制.但是,授权配置中运行guests群组中的用户消费来自STOCKS.ORCL主题中的消息,如下所示:
  

$ mvn exec:java -Dexec.mainClass=org.apache.activemq.book.ch6.Consumer -Dexec.args="STOCKS.ORCL"
(译注: 貌似-Dexec.args参数值应该为 -Dexec.args="ORCL" 否则出错,因为配置有权限的topic为STOCKS.ORCL,
代码中使用这个参数语句为:createTopic("STOCKS." + stock);
修改后的命令为: mvn exec:java -Dexec.mainClass=org.apache.activemq.book.ch6.Consumer -Dexec.args="ORCL")
...
ORCL 9.66 9.67 down
ORCL 9.70 9.71 up
ORCL 9.80 9.81 up
ORCL 9.83 9.84 up
ORCL 9.80 9.81 down
ORCL 9.75 9.76 down
ORCL 9.81 9.82 up
ORCL 9.88 9.89 up
ORCL 9.80 9.81 down
ORCL 9.84 9.85 up
ORCL 9.84 9.85 up
ORCL 9.86 9.87 up
ORCL 9.95 9.96 up
ORCL 10.03 10.04 up
ORCL 10.03 10.04 down
...

 As you can see, the authorization settings allowed only read access to the STOCKS.ORCL topic for users that belong to the guests group.

These simple examples demonstrate how easy it is to secure ActiveMQ destinationsand assign different security levels to various users and groups. But what if definingthe access levels per destination isn’t enough for your application’s needs? Luckily,ActiveMQ allows you to do a message-based authorization as well.

 正如你看到的那样,授权设置只允许来自guests群组的用户读取来自STOCKS.ORCL主题的消息.

这些简单的例子说明,对ActiveMQ进行安全控制并为不同的群组和用户设置不同的安全等级是相当容易的.但是,假如在消息目的地级别进行访问控制已不能完全符合应用需求时,改如何操作? 很幸运的是,ActiveMQ还允许你进行基于消息级别的授权.

 6.2.2 Message-level authorization

So far in this chapter, we’ve covered broker-level authentication and authorization.But as you can see, authorization was granted or denied in the process of creating aconnection to the broker. In some situations you might want to authorize access toonly particular messages in a destination. In this section, we’ll examine such messagelevel authorization.

We’ll implement a simple authorization plug-in that allows only applications runningon the same host as the broker (the localhost) to consume messages. The firstthing we need to do is to create an implementation of the org.apache.activemq.security.MessageAuthorizationPolicy interface, as shown in the following listing.

Listing 6.3 Implementation of MessageAuthorizationPolicy interface

 6.2.2 消息级别的授权

到目前为止,我们已经介绍了代理界别的认证和授权.但是,正如你所看到的,授权被允许或拒绝的过程都是发生在创建到代理的连接时.有些情况下,你可能需要授权仅仅针对某个消息目的地中的某个消息.本节中我们将讨论这种消息级别的授权.

我们将实现一个简单授权插件,该插件仅允许与代理(localhost)在同一机器上的应用程序消费消息.首先我们要做的就是实现org.apache.activemq.security.MessageAuthorizationPolicy的接口,如下所示.

代码清单6.3 实现MessageAuthorizationPolicy接口

 

public class AuthorizationPolicy implements MessageAuthorizationPolicy 
{
  private static final Log LOG = LogFactory.getLog(AuthorizationPolicy.class);
  
  public boolean isAllowedToConsume(ConnectionContext context,Message message) 
  {
    LOG.info(context.getConnection().getRemoteAddress());
    String remoteAddress = context.getConnection().getRemoteAddress();
    if (remoteAddress.startsWith("/127.0.0.1")) 
    {
      LOG.info("Permission to consume granted");
      return true;
    } 
    else 
    {
      LOG.info("Permission to consume denied");
      return false;
    }
  }
}

 As you can see, the MessageAuthorizationPolicy interface is simple and defines onlyone method named isAllowedToConsume(). This method has access to the messagein question and the context of the connection in which the message will be consumed.

In this example, the remote address property for a connection is used (via thecall to the Connection.getRemoteAddress() method) to distinguish a remote consumerfrom a local consumer. The isAllowedToConsume() method then determineswhether the read operation is allowed for the given consumer. Of course, this implementationis arbitrary. You can use any message property or even some message contentto make the determination. The implementation of this method is meant to be asimple example.

 如上述代码所示,MessageAuthorizationPolicy接口很简单只有一个方法isAllowedToConsume().这个方法可以访问需要权限控制的消息以及消息上下文中的连接(通过该连接,消息将会被消费).

在这个示例代码中,使用connection的远程地址属性值(通过Connection.getRemoteAddress()方法获取)来区分远程的消息消费者是否是一个本地的消费者.接着,isAllowedToConsume()方法决定是否允许当前的消息消费者进行读取消息的操作.当然,这个实现有些随意,你可以使用消息的任何属性甚至消息内容来决定当前消费者能否消费该消息.这里的实现仅仅作为一个简单的示例.

 Now this policy must be installed and configured in the ActiveMQ broker. The firstand most obvious step is to compile this class and package it in an appropriate JAR.Place this JAR into the lib/ directory of the ActiveMQ distribution and the policy isready to be used. You can do that by building and copying the book examples JAR:  接下来,这个消息访问控制策略必须要安装并配置到ActiveMQ的代理中.首先,显而易见的步骤是编译这个类并打包为适当的Jar文件.然后将改Jar文件放到ActiveMQ得到lib目录下面.你可以使用下面的命令编译并拷贝实例Jar包到ActiveMQ得到lib目录下面:
$ mvn clean install
...
$ cp target/activemq-in-action-examples.jar ${ACTIVEMQ_HOME}/lib/
 Second, the policy must be configured to create an instance of the Authorization-Policy class in the ActiveMQ XML configuration file. Using the Spring beans–styleXML inside the <messageAuthorizationPolicy> element, the AuthorizationPolicyclass is instantiated when the broker starts up. Here’s an example of this configuration:  接着,必须在ActiveMQ的XML配置文件中配置策略并创建一个AuthorizationPolicy类的引用.使用Spring的bean风格的配置在<messageAuthorizationPolicy>元素中配置一个bean,是的AuthorizationPolicy类在代理启动时能够被实例化.下面是配置的实例代码:
  

...
<messageAuthorizationPolicy>
  <bean class="org.apache.activemq.book.ch6.AuthorizationPolicy" xmlns="http://www.springframework.org/schema/beans" />
</messageAuthorizationPolicy>
...
 The only step left is to start up ActiveMQ and test out the new policy. Here’s the command to start up the broker using the appropriate configuration file:  接着需要启动ActiveMQ以便测试新的授权策略.下面是以相应的配置文件启动代理的命令:
  

${ACTIVEMQ_HOME}/bin/activemq console xbean:src/main/resources/org/apache/activemq/book/ch6/activemq-policy.xml
(window下命令:%ACTIVEMQ_HOME%/bin/activemq  xbean:src/main/resources/org/apache/activemq/book/ch6/activemq-policy.xml)
...
Loading message broker from:
xbean:src/main/resources/org/apache/activemq/book/ch6/activemq-policy.xml
...
22:19:23,532 | INFO | PListStore:/Users/bsnyder/amq/apache-activemq-5.4.1/data/localhost/tmp_storage started
22:19:23,692 | INFO | JMX consoles can connect to service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi
22:19:23,717 | INFO | Using Persistence Adapter: KahaDBPersistenceAdapter[/Users/bsnyder/amq/apache-activemq-5.4.1/data/localhost/KahaDB]
22:19:23,815 | DEBUG | loading
22:19:23,847 | INFO | ActiveMQ 5.4.1 JMS Message Broker (localhost) is starting
22:19:23,848 | INFO | For help or more information please see: http://activemq.apache.org/
22:19:23,990 | INFO | Scheduler using directory:/Users/bsnyder/amq/apache-activemq-5.4.1/data/localhost/scheduler
22:19:24,037 | DEBUG | loading
22:19:24,039 | DEBUG | loading
22:19:24,041 | INFO | JobSchedulerStore:/Users/bsnyder/amq/apache-activemq-5.4.1/data/localhost/scheduler started
22:19:24,081 | INFO | Listening for connections at: tcp://localhost:61616
22:19:24,081 | INFO | Connector openwire Started
22:19:24,083 | INFO | ActiveMQ JMS Message Broker(localhost, ID:mongoose.local-64256-1289971163870-0:0) started
...
 If you run the examples from chapter 3 now on the host on which your broker is running,you’ll see that everything works in the same manner as it did with the originalconfiguration. The producer produces messages:  如果你在运行代理的机器上运行第3章中的例子,你会发现所有程序工作正常,就像使用前面的配置一样.
producer发布消息的命如下:
  

$ mvn exec:java -Dexec.mainClass=org.apache.activemq.book.ch3.portfolio.Publisher -Dexec.args="CSCO ORCL"
...
Sending: {price=94.51516220513759, stock=ORCL, offer=94.60967736734271,up=true} on destination: topic://STOCKS.ORCL
Sending: {price=94.12582896629408, stock=ORCL, offer=94.21995479526036,up=false} on destination: topic://STOCKS.ORCL
Sending: {price=52.82279394171494, stock=CSCO, offer=52.87561673565665,up=false} on destination: topic://STOCKS.CSCO
Sending: {price=93.30370880341836, stock=ORCL, offer=93.39701251222176,up=false} on destination: topic://STOCKS.ORCL
Sending: {price=94.0890269658999, stock=ORCL, offer=94.1831159928658,up=true} on destination: topic://STOCKS.ORCL
Sending: {price=52.50790406130471, stock=CSCO, offer=52.56041196536601,up=false} on destination: topic://STOCKS.CSCO
Sending: {price=94.11072880595002, stock=ORCL, offer=94.20483953475596,up=true} on destination: topic://STOCKS.ORCL
Sending: {price=52.947263764976896, stock=CSCO, offer=53.000211028741866,up=true} on destination: topic://STOCKS.CSCO
Sending: {price=94.40912590172766, stock=ORCL, offer=94.50353502762938,up=true} on destination: topic://STOCKS.ORCL
Sending: {price=95.0802935408136, stock=ORCL, offer=95.1753738343544,up=true} on destination: topic://STOCKS.ORCL
Published '10' of '10' price messages
 And the consumer receives these stock messages:  consumer接收消息命令如下:
  

$ mvn exec:java -Dexec.mainClass=org.apache.activemq.book.ch3.portfolio.Consumer -Dexec.args="CSCO ORCL"
...
ORCL 94.52 94.61 up
ORCL 94.13 94.22 down
CSCO 52.82 52.88 down
ORCL 93.30 93.40 down
ORCL 94.09 94.18 up
CSCO 52.51 52.56 down
ORCL 94.11 94.20 up
CSCO 52.95 53.00 up
ORCL 94.41 94.50 up
ORCL 95.08 95.18 up
CSCO 52.90 52.96 down
ORCL 95.62 95.71 up
CSCO 53.32 53.37 up
ORCL 95.45 95.55 down
CSCO 53.59 53.64 up
...
 You can also notice log messages from the policy in the broker’s console:  你可以看到运行代理的控制台窗口会打印以下信息:
  

INFO | /127.0.0.1:50930
INFO | Permission to consume granted
INFO | /127.0.0.1:50930
INFO | Permission to consume granted
INFO | /127.0.0.1:50930
INFO | Permission to consume granted
INFO | /127.0.0.1:50930
INFO | Permission to consume granted
INFO | /127.0.0.1:50930
INFO | Permission to consume granted
INFO | /127.0.0.1:50930
INFO | Permission to consume granted
 But, when run from another host (for example, 192.168.10.10), the consumer won’t be able to consume messages, as our policy will deny the access. And you’ll notice log messages similar to these in the broker’s console:  但是,假如在其他机器上(比如在192.168.10.10)运行consumer,consumer将不能消费消息,因为前面的策略拒绝了consumer访问消息.你将在运行consumer的控制台上看到类型下面的日志信息:
  

INFO | /192.168.10.10:50930
INFO | Permission to consume denied
INFO | /192.168.10.10:50930
INFO | Permission to consume denied
INFO | /192.168.10.10:50930
INFO | Permission to consume denied
INFO | /192.168.10.10:50930
INFO | Permission to consume denied
INFO | /192.168.10.10:50930
INFO | Permission to consume denied
INFO | /192.168.10.10:50930
INFO | Permission to consume denied

 In this way, we verified that our message-based policy works and enables message consumption only from the local host.

 通过这种方式,我们验证了基于消息的安全策略能够正常工作并且保证只有来自本地机器的消息消费者能消费消息.

Message-level authorization provides some powerful functionality with endless possibilities.Although a simple example was used here, you can adapt it to any securitymechanism used in your project. Just bear in mind that a message authorization policyis executed for every message that flows through the broker. So be careful not toadd functionality that could possibly slow down the flow of messages.

消息级的授权提供了一些强大的功能与无限的可能性。尽管这里使用的仅仅是一个简单的示例,但你可以将消息级别的授权扩展使用任意安全机制的工程中.需要注意的是消息授权策略将影响该代理中的所有消息.所以,需要注意不要因为增加消息验证的功能额拖慢了消息的传送.

In addition to authorization, ActiveMQ provides a special class for tighter controlover broker-level operations that’s even more powerful. The next section examinesand demonstrates just such an example.

除了授权机制外,ActiveMQ还提供一种特殊的类以便能够更紧密的控制代理级别的操作,进而提供更加强大的功能.下面的章节中,我们将以一个实例来说明.

赞 赏

   微信赞赏  支付宝赞赏


本文固定链接: https://www.jack-yin.com/coding/translation/activemq-in-action/1033.html | 边城网事

该日志由 边城网事 于2013年10月28日发表在 ActiveMQ in Action 读书笔记 分类下, 你可以发表评论,并在保留原文地址及作者的情况下引用到你的网站或博客。
原创文章转载请注明: 6.2 activeMQ 授权 Authorization | 边城网事

6.2 activeMQ 授权 Authorization 暂无评论

发表评论

快捷键:Ctrl+Enter