场景--由于azkaban管理用户是通过配置xml来实现的,不太符合我司需求,所以写了一个从mysql数据库读取用户的插件替换azkaban默认的用户管理,但是目前只是实现了从数据库读取数据,想要新增用户的话只能按照表的格式导入到数据库,这里主要说的是思路,只贴出关键部分的代码,源码,编译后的jar包,以及sql文件我会上传到下载目录下供用户下载
azkaban的安装参考 azkaban3.12 编译与安装 - shp5174的博客 - 博客频道 - CSDN.NET
导入jar包
因为azkaban的用户手册上说明定制用户需要实现 UserManager接口所以创建一个java工程
并导入azkaban-common.xxx.jar包,UserManager接口在这个jar包中,再导入一些必要的jar包,如图
创建util连接数据库
懂java的应该都看的懂,就是平时用java连接数据库的方式,所以这里只简单说一下
先创建一个property文件,用来保存连接参数,
内容如下
url = jdbc:mysql://10.80.2.7/azkaban
name = com.mysql.jdbc.Driver
user = azkaban
password = azkaban
创建jdbc类用来读取这份配置文件
关键部分代码如下
/**
* 私有构造方法,不需要创建对象
*/
private Jdbc() {
Properties prop = new Properties();
InputStream in = Object.class.getResourceAsStream("/resource/jdbc.properties");
try {
prop.load(in);
url = prop.getProperty("url").trim();
name = prop.getProperty("name").trim();
user = prop.getProperty("user").trim();
password = prop.getProperty("password").trim();
} catch (IOException e) {
e.printStackTrace();
}
}
private static final Jdbc jdbc = new Jdbc();
// 静态方法返回该类的实例
public static Jdbc getInstance() {
return jdbc;
}
创建JdbcFactory类来真正连接数据库
关键部分代码如下
private JdbcFactory() {
Jdbc jdbc=Jdbc.getInstance();
url=jdbc.getUrl();
name=jdbc.getName();
user=jdbc.getUser();
password=jdbc.getPassword();
try {
Class.forName(name);//指定连接类型
conn = DriverManager.getConnection(url, user, password);//获取连接
} catch (Exception e) {
e.printStackTrace();
}
}
另外还针对我的设计,写了一个定制的查询数据库语句,之所以是定制,是因为这个方法并不能通用,只符合我目前的需求
public void getConnection() {
if(conn ==null) {
try {
Class.forName(name);//指定连接类型
conn = DriverManager.getConnection(url, user, password);//获取连接
} catch (Exception e) {
e.printStackTrace();
}
}
}
public List
this.getConnection();
List
try {
pst = conn.prepareStatement(sql);//准备执行语句
//设置参数
for(int i=0;i
}
String s=pst.toString();
System.out.println("==========sql:"+s.substring(s.indexOf("SELECT")));
ResultSet rs=pst.executeQuery();
while (rs.next()) {
resultList.add(rs.getString(1));
}
rs.close();
// this.close();
} catch (SQLException e) {
e.printStackTrace();
}
return resultList;
}
util的准备到此结束
数据库表的设计
DROP TABLE IF EXISTS `group`;
CREATE TABLE `group` (
`name` varchar(255) NOT NULL,
`create_time` varchar(255) DEFAULT NULL,
PRIMARY KEY (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC;
-- ----------------------------
-- Records of group
-- ----------------------------
INSERT INTO `group` VALUES ('admin', null);
INSERT INTO `group` VALUES ('azkaban', null);
INSERT INTO `group` VALUES ('test1', null);
-- ----------------------------
-- Table structure for `group_role`
-- ----------------------------
DROP TABLE IF EXISTS `group_role`;
CREATE TABLE `group_role` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`group_name` varchar(255) DEFAULT NULL,
`role_name` varchar(255) DEFAULT NULL,
`create_time` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=5 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC;
-- ----------------------------
-- Records of group_role
-- ----------------------------
INSERT INTO `group_role` VALUES ('3', 'admin', 'admin', null);
-- ----------------------------
-- Table structure for `role`
-- ----------------------------
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
`name` varchar(255) NOT NULL,
`create_time` varchar(255) DEFAULT NULL,
PRIMARY KEY (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC;
-- ----------------------------
-- Records of role
-- ----------------------------
INSERT INTO `role` VALUES ('admin', null);
INSERT INTO `role` VALUES ('azkaban', null);
INSERT INTO `role` VALUES ('test1', null);
-- ----------------------------
-- Table structure for `role_permission`
-- ----------------------------
DROP TABLE IF EXISTS `role_permission`;
CREATE TABLE `role_permission` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`role_name` varchar(255) DEFAULT NULL,
`permission` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=latin1;
-- ----------------------------
-- Records of role_permission
-- ----------------------------
INSERT INTO `role_permission` VALUES ('1', 'admin', 'ADMIN');
INSERT INTO `role_permission` VALUES ('2', 'azkaban', 'ADMIN');
INSERT INTO `role_permission` VALUES ('4', 'test1', 'WRITE');
-- ----------------------------
-- Table structure for `user`
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`name` varchar(255) NOT NULL,
`password` varchar(255) NOT NULL,
`email` varchar(255) DEFAULT NULL,
`create_time` varchar(255) DEFAULT NULL,
PRIMARY KEY (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('azkaban', 'azkaban', null, null);
INSERT INTO `user` VALUES ('admin', 'admin', null, null);
INSERT INTO `user` VALUES ('test1', 'test1', null, null);
-- ----------------------------
-- Table structure for `user_group`
-- ----------------------------
DROP TABLE IF EXISTS `user_group`;
CREATE TABLE `user_group` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`group_name` varchar(255) DEFAULT NULL,
`user_name` varchar(255) DEFAULT NULL,
`create_time` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC;
-- ----------------------------
-- Records of user_group
-- ----------------------------
INSERT INTO `user_group` VALUES ('3', 'admin', 'admin', null);
-- ----------------------------
-- Table structure for `user_role`
-- ----------------------------
DROP TABLE IF EXISTS `user_role`;
CREATE TABLE `user_role` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_name` varchar(255) DEFAULT NULL,
`role_name` varchar(255) DEFAULT NULL,
`create_time` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=latin1;
-- ----------------------------
-- Records of user_role
-- ----------------------------
INSERT INTO `user_role` VALUES ('1', 'admin', 'admin', null);
INSERT INTO `user_role` VALUES ('2', 'azkaban', 'azkaban', null);
INSERT INTO `user_role` VALUES ('3', 'test1', 'test1', null);
有些表可能在逻辑里并没有用到,懒得修改了.
实现UserManager接口
其中需要实现的只有getRole,getUser两个方法,其他的默认返回就行了
首先说说getUser方法
这个方法要做的事是,传入用户名和密码,返回一个user对象,这个user对象包属性如下:
private final String userid;
private String email = "";
private Set
private Set
private UserPermissions userPermissions;
可以看出这个用户的角色和群组都用用set保存起来了
所以我在getUser方法中是这么写的
public User getUser(String userName, String password) throws UserManagerException {
if (userName == null || userName.trim().isEmpty()) {
throw new UserManagerException("请输入账号");
} else if (password == null || password.trim().isEmpty()) {
throw new UserManagerException("请输入密码");
}
//查询用户名和密码是否正确
String existSql ="SELECT name FROM user u where u.name=? and u.`password`=?";
if(jf.find(existSql, userName,password).size()==0) {
throw new UserManagerException("账号密码错误或不存在");
}
User user = new User(userName);
//查询用户拥有的group
String findRoleSql="SELECT group_name FROM user_group ug where ug.user_name=?";
List
//用户可能没有group,因为在设置的时候可以直接为用户指定角色,而跳过group这一步
if(groups.size()>0) {
for(String group:groups) {
user.addGroup(group);
}
}
//同理查询用户角色,并保存到到 role中,用户的角色来源分为两部分一种是group下的角色组,一种是用户直接分配的角色
String findperMissionSql="SELECT gr.role_name from user_group ug,group_role gr "
+"where ug.user_name=? and ug.group_name=gr.group_name union "
+"select ur.role_name from user_role ur where ur.user_name=?";
List
if(roles.size()>0) {
for(String role:roles) {
user.addRole(role);
}
}
return user;
}
再来看 getRole方法,这个方法要做的事是传入一个角色名,返回一个包含该角色拥有的权限的角色类
Role类的属性如下
private final String name;
private final Permission globalPermission;
getRole方法的实现如下:
public Role getRole(String roleName) {
String findRoleSql="SELECT rp.permission FROM role_permission rp where rp.role_name=?";
List
Role role=null;
if(permissions.size()>0) {
Permission perm = new Permission();
for (String permString : permissions) {
try {
Permission.Type type = Permission.Type.valueOf(permString);
perm.addPermission(type);
} catch (IllegalArgumentException e) {
logger.error("Error adding type " + permString
+ ". Permission doesn't exist.", e);
}
}
role = new Role(roleName, perm);
}
return role;
}
到目前,功能代码实现完了,但是由于我忽略了官方文档的一句话,所以导致调试了很久都运行不了;
The constructor should take an azkaban.utils.Props
object. The contents of azkaban.properties
will be available for the UserManager for configuration.
定制的用户管理类必须要有一个参数为Props的构造方法,这个构造方法用来获取azkaban.properties文件的路径.
public MyUserManager(Props props) {
xmlPath = props.getString(XML_FILE_PARAM);
}
把几个类打成jar包,丢到extlib文件夹中
jar包不需要添加到这次打包的jar包中,因为这些包之前就存在的.
修改azkaban.properties中的用户管理默认类
user.MyUserManager是class文件的路径
最后重启azkaban就可以了
原谅我一点私心:源码,jar包以及sql文件请从下载页面下载