activemq自定義安全驗證外掛,整合mysql
阿新 • • 發佈:2018-12-20
一.下載外掛程式碼所需jar包,我是在maven中引入,然後再copy到activemq的指定目錄:
<dependencies> <!-- https://mvnrepository.com/artifact/org.apache.activemq/activemq-broker --> <dependency> <groupId>org.apache.activemq</groupId> <artifactId>activemq-broker</artifactId> <version>5.15.8</version> </dependency> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>6.0.6</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>4.3.18.RELEASE</version> </dependency> </dependencies>
將mysql-connector-java-6.0.6.jar包copy到C:\apache-activemq-5.15.8\lib目錄下,將spring-jdbc-4.3.18.RELEASE.jar包copy到C:\apache-activemq-5.15.8\lib\optional目錄下。注意:spring-jdbc版本要和C:\apache-activemq-5.15.8\lib\optional目錄下的spring版本相同。
二.編輯C:\apache-activemq-5.15.8\conf下的activemq.xml,<bean>節點配置改為:
<!-- 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> <!-- Allows accessing the server log --> <bean id="logQuery" class="io.fabric8.insight.log.log4j.Log4jLogQuery" lazy-init="false" scope="singleton" init-method="start" destroy-method="stop"> </bean> <!-- 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> <!-- 增加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>
然後在<broker>節點中的最後新增配置:
<plugins> <bean xmlns="http://www.springframework.org/schema/beans" id="myPlugin" class="my.plugin.MyAuthenticationPlugin"> <constructor-arg> <ref bean="jdbcTemplate"/> </constructor-arg> </bean> </plugins> </broker>
其中db.properties是自己新建的配置檔案,內容如下:
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/yzh?autoReconnect=true&useUnicode=true&characterEncoding=utf8&useSSL=false
jdbc.username=root
jdbc.password=123456
建立好後copy到C:\apache-activemq-5.15.8\conf目錄下。
這樣服務端的配置就完成了,下面是自定義外掛的程式碼。
三.認證外掛的編碼:
package my.plugin;
import org.apache.activemq.broker.Broker;
import org.apache.activemq.broker.BrokerPlugin;
import org.springframework.jdbc.core.JdbcTemplate;
import java.util.List;
/**
* description:
* author:
* date: 2018-12-07 09:54
**/
public class MyAuthenticationPlugin implements BrokerPlugin {
JdbcTemplate jdbcTemplate;//注入JdbcTemplate
public MyAuthenticationPlugin(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public Broker installPlugin(Broker broker) throws Exception {
return new MyAuthenticationBroker(broker,jdbcTemplate);
}
}
其中MyAuthenticationBroker的編碼:
package my.plugin;
import org.apache.activemq.broker.Broker;
import org.apache.activemq.broker.BrokerFilter;
import org.apache.activemq.broker.ConnectionContext;
import org.apache.activemq.command.ConnectionInfo;
import org.apache.activemq.security.AbstractAuthenticationBroker;
import org.apache.activemq.security.SecurityContext;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import java.security.Principal;
import java.security.cert.X509Certificate;
import java.util.*;
import java.util.regex.Pattern;
/**
* description: broker的實現,附帶方法過濾
* author: yangzihe
* date: 2018-12-07 09:50
**/
public class MyAuthenticationBroker extends AbstractAuthenticationBroker {
private JdbcTemplate jdbcTemplate;
public MyAuthenticationBroker(Broker next, JdbcTemplate jdbcTemplate) {
super(next);
this.jdbcTemplate = jdbcTemplate;
}
/**
* 建立連線的時候攔截
*
* @param context
* @param info
* @throws Exception
*/
@Override
public void addConnection(ConnectionContext context, ConnectionInfo info) throws Exception {
SecurityContext securityContext = context.getSecurityContext();
if (securityContext == null) { System.out.println("============================================username=" + info.getUserName() + ",password=" + info.getPassword());
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);
throw e;
}
}
/**
* 查詢資料庫獲取user,優化:載入時將資料庫所有user放入記憶體
*
* @param username
* @return
*/
private User getUser(String username) {
String sql = "select * from db_user where username=? limit 1";
try {
User user = jdbcTemplate.queryForObject(sql, new Object[]{username}, new BeanPropertyRowMapper<User>(User.class));
return user;
} catch (EmptyResultDataAccessException e) {
return null;
}
}
public static Map<String, User> map = null;
public void getAllUser() {
String sql = "select * from db_user";
List<User> list = jdbcTemplate.query(sql, new BeanPropertyRowMapper<User>(User.class));
map = new LinkedHashMap<String, User>();
for (User user : list) {
System.err.println(user);//debug
map.put(user.getUser_name(), user);
}
}
/**
* 認證
*
* @param username
* @param password
* @param peerCertificates
* @return
* @throws SecurityException
*/
public SecurityContext authenticate(String username, String password, X509Certificate[] peerCertificates) throws SecurityException {
SecurityContext securityContext = null;
// User user = getUser(username);
if (map == null || map.size() <= 0) {
System.out.println("==============連線mysql=================");
getAllUser();
}
User user = map.get(username);//記憶體中獲取
//驗證使用者資訊
if (user != null && user.getPass_word().equals(password)) {
securityContext = new SecurityContext(username) {
@Override
public Set<Principal> getPrincipals() {
Set<Principal> groups = new HashSet<Principal>();
//groups.add(new GroupPrincipal("users"));//預設加入了users的組
return groups;
}
};
} else {
throw new SecurityException("my auth plugin authenticate failed");
}
return securityContext;
}
}
其中User是資料庫表db_user的對映實體類:
package my.plugin;
/**
* description:
* author: yangzihe
* date: 2018-12-07 16:25
**/
public class User {
private String user_name;
private String pass_word;
@Override
public String toString() {
return "User{" +
"user_name='" + user_name + '\'' +
", pass_word='" + pass_word + '\'' +
'}';
}
public User() {
}
public User(String user_name, String pass_word) {
this.user_name = user_name;
this.pass_word = pass_word;
}
public String getUser_name() {
return user_name;
}
public void setUser_name(String user_name) {
this.user_name = user_name;
}
public String getPass_word() {
return pass_word;
}
public void setPass_word(String pass_word) {
this.pass_word = pass_word;
}
}
最後,資料庫表的sql:
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for db_user
-- ----------------------------
DROP TABLE IF EXISTS `db_user`;
CREATE TABLE `db_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,
`pass_word` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of db_user
-- ----------------------------
INSERT INTO `db_user` VALUES (1, 'admin', 'admin');
SET FOREIGN_KEY_CHECKS = 1;
四.activemq broker服務端配置修改和外掛程式碼的編寫都已完成,最後就是啟動activemq,cmd進入C:\apache-activemq-5.15.8\bin,執行activemq start,或者直接找對應的64位的activemq.bat執行檔案雙擊。服務啟動後,客戶端再次連線的時候,username=admin password=admin,如果不是將連線失敗。(在外掛程式碼中可自定義自己的驗證邏輯)