对于权限来说有很多框架比如shiro,spring security,但是都不能满足我所作的权限细度要求,也没有时间学习,所以我决定自己设计一套,对于权限来说我个人觉着可能直接对url进行赋权限比较方便和合理,在2年前第一创业的时候要做一套saas的微信,crm,oa,系统,当时的想法挺简单就是使用filter来做,权限机构设计则是:用户,角色,权限,如图:
当时使用的mysql 直接设计的model进行的。
在使用过程中出现登录缓慢,每一次打开新的url时要判断权限,权限关系又略微复杂,每次都要重复添加权限在一个角色权限关联表里。
缺点:
1.数据量每多一个角色会多很多数据。
2.查询条件过于复杂每一次访问url造成好几秒的权限读取。非常缓慢
当时的解决方案:
在每次登陆的时候吧权限统一加载出来,房子session内。
缺点:
登陆的时候依旧很慢。
优点:
在登录后访问其他按钮,页面时会快很多倍。
在去年,创业失败后我来到杭州,进入一家资产管理公司,要求设计一套有权限的系统,对于每个按钮都需要分配权限。所以我又从新设计了一下
思路是这样的:
上次造成数据非常多,查询非常复杂是因为所有信息都存在mysql,数据结构设计的不恰当所致,这次我就想如果每个用户单独直接有一个权限列表的话是不是就可以快很多。
所以我启用了redis进行记录方便快速查询,mysql 记录详细关联信息用于增删改
redis内部设计是这样的结构:
用户和权限表:
key:[用户id]ulp,value:(key:url,value:[角色Id1,角色Id2,角色Id3,角色Id4,])
//相当于map内套map
第一个key 是用用户id+“ulp”字符串组成,用于登录使用时快速查询一个用户的所有权限列表,
第一个value内部key是权限的url 这样在filter内直接可以获取url后去权限列表读,如果返回为null时则不存在改权限了。
第二个value 是该权限分别属于这个用户多个角色中那几个角色赋予的,这样在删除一个角色时如果有其他角色给于用户此权限,那么该权限还会存在,如果只有一个角色的话那么改权限会在权限列表中被删除。
结构图
https://github.com/dcl8261425/saas 微信+crm+进销存+oa 的项目已经放出。
/**
* 主要作用是对redis 进行添加删除操作,从而达到与mysql同步
*
* @author 董成龙 email:dcl8261425@gmail.om
*/
public class PermissionRedis {
private Jedis jedis;
public PermissionRedis() {
if (jedis == null) {
jedis = JedisManager.getJedis();
}
}
/**
* 向用户添加角色 用户连接权限连接角色
*
* @return
*/
public boolean addRoleToUser(long roleId, long userId, PermissionService dao) {
try {
List<RoleLinkPermission> list = dao.queryRolePermission(roleId);
// 获取用户权限信息
Map<String, String> userMap = jedis.hgetAll("ulplr" + userId + "");
// 检测是否有此用户的权限信息
if (userMap == null || userMap.size() <= 0) {
// 没有则添加一个进去
userMap = new HashMap<String, String>();
}
// 创建迭代器
Iterator<RoleLinkPermission> i = list.iterator();
// 循环查找是否有权限
while (i.hasNext()) {
RoleLinkPermission p = i.next();
String s = userMap.get(p.getPermissionUrl());
// 判断是否为空或者空字符串,如果是的话则添加第一个,不是的话多添加一个,分隔符,用于后期处理
if (s == null || s.equals("")) {
userMap.put(p.getPermissionUrl(), roleId + "");
} else {
userMap.put(p.getPermissionUrl(), s + "," + roleId);
}
}
if(userMap.size()==0){
userMap.put("", "");
}
jedis.hmset("ulplr" + userId + "", userMap);
// 把用户加入角色的列表,这样在后期处理时可以做添加删除
Map<String, String> rlu = jedis.hgetAll("rlu" + roleId);
AdminUser user = (AdminUser) dao.loadBean(userId, AdminUser.class);
if (rlu == null) {
rlu = new HashMap<String, String>();
}
rlu.put("" + userId, user.getName());
jedis.hmset("rlu" + roleId, rlu);
return true;
} catch (Exception ext) {
ext.printStackTrace();
return false;
} finally {
}
}
/**
* 添加权限到角色
*
* @return
*/
public boolean addPermissionToRole(String permissionUrl, long roleId, PermissionService dao) {
try {
Map<String, String> rlu = jedis.hgetAll("rlu" + roleId);
Set<String> set = rlu.keySet();
Iterator<String> i = set.iterator();
// 查询所有拥有此角色的用户,并添加权限
while (i.hasNext()) {
String userId = i.next();
Map<String, String> userMap = jedis.hgetAll("ulplr" + userId);
String roles = userMap.get(permissionUrl);
if (roles != null && !roles.equals("")) {
// 如果该用户已经拥有此权限,则向角色列表中添加角色
StringBuffer s = new StringBuffer(roles);
s.append(",").append(roleId);
userMap.put(permissionUrl, s.toString());
} else {
// 如果该用户没有此权限,则添加权限
userMap.put(permissionUrl, roleId + "");
}
// 从新放入redis中
jedis.hmset("ulplr" + userId, userMap);
}
return true;
} catch (Exception ext) {
ext.printStackTrace();
return false;
} finally {
}
}
/**
* 删除角色从用户
*
* @return
*/
public boolean deleteRoleFromUser(long roleId, long userId, PermissionService dao) {
try {
Map<String, String> permissions = jedis.hgetAll("ulplr" + userId);
List<RoleLinkPermission> rlps = dao.queryRolePermission(roleId);
Iterator<RoleLinkPermission> i = rlps.iterator();
while (i.hasNext()) {
RoleLinkPermission rp = i.next();
String roleids = permissions.get(rp.getPermissionUrl());
if (roleids != null && !roleids.equals("")) {
String[] ids = roleids.split(",");
if (ids.length > 1) {
StringBuffer sb = new StringBuffer();
for (int ii = 0; ii < ids.length; ii++) {
if (Long.parseLong(ids[ii]) != roleId) {
// 不是角色的话加入新的id组
if (sb.length() > 0) {
sb.append(",").append(ids[ii]);
} else {
sb.append(ids[ii]);
}
}
}
permissions.put(rp.getPermissionUrl(), sb.toString());
jedis.hset("ulplr" + userId, rp.getPermissionUrl(), sb.toString());
} else {
permissions.remove(rp.getPermissionUrl());
jedis.hdel("ulplr" + userId, rp.getPermissionUrl());
}
}
}
if (permissions.size() > 0) {
jedis.hmset("ulplr" + userId, permissions);
} else {
jedis.del("ulplr" + userId);
}
Map<String, String> uids = jedis.hgetAll("rlu" + roleId);
uids.remove(String.valueOf(userId));
if (uids.size() > 0) {
} else {
jedis.del("rlu" + roleId);
}
return true;
} catch (Exception ext) {
ext.printStackTrace();
return false;
} finally {
}
}
/**
* 删除权限从角色
*
* @return
*/
public boolean deletePermissionFromRole(long roleId, String permissionUrl, PermissionService dao) {
try {
Map<String, String> rlu = jedis.hgetAll("rlu" + roleId);
Set<String> s = rlu.keySet();
Iterator<String> i = s.iterator();
// 差选所有拥有角色的用户id
while (i.hasNext()) {
String userid = i.next();
// 查询角色拥有的权限
Map<String, String> permissions = jedis.hgetAll("ulplr" + userid);
// 获取此用户的权限角色列表
String rid = permissions.get(permissionUrl);
String[] rids = rid.split(",");
if (rids.length > 1) {
StringBuffer sb = new StringBuffer();
for (int ii = 0; ii < rids.length; ii++) {
if (Long.parseLong(rids[ii]) != roleId) {
if (sb.length() == 0) {
sb.append(rids[ii]);
} else {
sb.append(",").append(rids[ii]);
}
}
}
permissions.put(permissionUrl, sb.toString());
jedis.hset("ulplr" + userid, permissionUrl, sb.toString());
} else {
permissions.remove(permissionUrl);
jedis.hdel("ulplr" + userid, permissionUrl);
}
if (permissions.size() > 0) {
} else {
jedis.del("ulplr" + userid);
}
}
return true;
} catch (Exception ext) {
ext.printStackTrace();
return false;
} finally {
}
}
/**
* 查询一个用户的权限
*
* @return
*/
public Map queryPermission(long userId, PermissionService dao) {
try{
Map map = jedis.hgetAll("ulplr" + userId);
return map;
}catch(Exception ext){
ext.printStackTrace();
return new HashMap<String, String>();
}finally {
}
}
public void close(){
jedis.close();
}
}