场景--由于azkaban管理用户是通过配置xml来实现的,不太符合我司需求,所以写了一个从mysql数据库读取用户的插件替换azkaban默认的用户管理,但是目前只是实现了从数据库读取数据,想要新增用户的话只能按照表的格式导入到数据库,这里主要说的是思路,只贴出关键部分的代码,源码,编译后的jar包,以及sql文件我会上传到下载目录下供用户下载
azkaban的安装参考 azkaban3.12 编译与安装 - shp5174的博客 - 博客频道 - .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<String> find(String sql,String... list) { this.getConnection(); List<String> resultList=new ArrayList<String>(); try { pst = conn.prepareStatement(sql);//准备执行语句 //设置参数 for(int i=0;i<list.length;i++) { pst.setString(i+1, list[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<String> roles = new HashSet<String>(); private Set<String> groups = new HashSet<String>(); 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<String> groups=jf.find(findRoleSql, userName); //用户可能没有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<String> roles=jf.find(findperMissionSql, userName,userName); 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<String> permissions=jf.find(findRoleSql, roleName); 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文件请从下载页面下载
