查看上篇文章通用数据级别权限的框架设计与实现(2)-数据权限的准备工作,我们开始数据列表的权限过滤.
原理:我们在做过滤列表时,根据用户权限自动注入到相关SQL中,实现相关过滤,如果拥有全部权限,则不生成相关SQL片段
- 首先我们来分析一下数据列表的SQL
- 能看到所有数据的SQL
SELECT
role.id,
role. CODE,
role. NAME
FROM
sys_auth_role role
where 1=1
- 根据登陆角色,看到的数据的SQL
-SELECT
role.id,
role. CODE,
role. NAME
FROM
sys_auth_role role
LEFT JOIN sys_auth_role_org_rel ror ON ror.role_id = role.id
WHERE
1 = 1
AND ror.org_id IN (123, 123456)
两者分析,差异是表的关联,及查询的条件。我们因些通过配置来生成具体的相关SQL片段
@Data
public class AuthFiledFilter {
/**
* 默认左连接
*/
private String tableRel = "left join ";
/**
* 关联table名称
*/
private String salveTableName;
/**
* 关联table别名
*/
private String salveTableOtherName;
/**
* 关联table字段
*/
private String salveTableField;
/**
* 主表别名
*/
private String masterTableOtherName;
/**
* 默认主表关联字段
*/
private String masterTableField = "id";
/**
* 查找用户ID
*/
private String searchUserField;
/**
* 获取相关的关联SQL
*
* @return
*/
public String getSqlRel() {
StringBuilder sb = new StringBuilder();
//增加一个空格,防止与主表靠得太近
sb.append(" ");
//sb.append(this.getMasterTableOtherName());
sb.append(" ");
sb.append(this.getTableRel());
sb.append(" ");
sb.append(this.getSalveTableName()).append(" ").append(this.getSalveTableOtherName());
sb.append(" on ").append(this.getSalveTableOtherName()).append(".").append(this.getSalveTableField()).append("=").append(this.getMasterTableOtherName()).append(".").append(this.getMasterTableField());
return sb.toString();
}
public String getCondictionSqlIn(List userList) {
StringBuilder sb = new StringBuilder();
sb.append(" and ");
sb.append(this.buildLogicIN(this.getSalveTableOtherName() + "." + this.getSearchUserField(), userList));
return sb.toString();
}
public String getCondictionSqlEq(Object userId) {
StringBuilder sb = new StringBuilder();
sb.append(" and ");
sb.append(this.getSalveTableOtherName() + "." + this.getSearchUserField()).append("=").append(userId);
return sb.toString();
}
/**
* 构造in语句,若valueList超过1000时,该函数会自动拆分成多个in语句
*
* @param item
* @param valueList
* @return item in (valueList)
*/
public String buildLogicIN(String item, List valueList) {
int n = (valueList.size() - 1) / 1000;
StringBuffer rtnStr = new StringBuffer();
Object obj = valueList.get(0);
boolean isString = false;
if (obj instanceof Character || obj instanceof String)
isString = true;
String tmpStr;
for (int i = 0; i <= n; i++) {
int size = i == n ? valueList.size() : (i + 1) * 1000;
if (i > 0)
rtnStr.append(" or ");
rtnStr.append(item + " in (");
if (isString) {
StringBuffer tmpBuf = new StringBuffer();
for (int j = i * 1000; j < size; j++) {
tmpStr = valueList.get(j).toString().replaceAll("'", "''");
tmpBuf.append(",'").append(tmpStr).append("'");
}
tmpStr = tmpBuf.substring(1);
} else {
tmpStr = valueList.subList(i * 1000, size).toString();
tmpStr = tmpStr.substring(1, tmpStr.length() - 1);
}
rtnStr.append(tmpStr);
rtnStr.append(")");
}
if (n > 0)
return "(" + rtnStr.toString() + ")";
else
return rtnStr.toString();
}
}
上述类中,生成的SQL片段方法为getSqlRel,getCondictionSqlIn,getCondictionSqlEq方法。
2.我们来生成各种权限校验的规则,Key用类的对象来实现
/**
* @description: 权限的全局配置
* @author: starmark
* @create: 2018-05-17 16:22
**/
public class AuthConfig {
//全局校验数据规则
public static Map<String,AuthValidatorModel> authMap=new HashMap();
/**
* 增加权限校验对象
* @param authValidatorModel
*/
public static void add(AuthValidatorModel authValidatorModel){
authMap.put(authValidatorModel.classModel,authValidatorModel);
}
/**
*获取权限校验规则
* @param classModel
* @return
*/
public static AuthValidatorModel get(String classModel){
return authMap.get(classModel);
}
}
在service类初始化时,将权限规则注入进去
public class SysAuthRoleServiceImpl implements ISysAuthRoleService,InitializingBean {...
/**
* 初始化权限校验模型
* @throws Exception
*/
@Override
public void afterPropertiesSet() throws Exception {
AuthValidatorModel authValidatorModel=new AuthValidatorModel(SysAuthRole.class.getName());
//角色user1与角色user2能看到所有数据
authValidatorModel.getRoles().add("user1");
authValidatorModel.getRoles().add("user2");
//构造关联查询的对象
AuthFiledFilter authFiledFilter=new AuthFiledFilter();
//主表别名
authFiledFilter.setMasterTableOtherName("role");
//从表表名
authFiledFilter.setSalveTableName("sys_auth_role_org_rel");
//从表另名
authFiledFilter.setSalveTableOtherName("ror");
//关联字段
authFiledFilter.setSalveTableField("role_id");
//查找用户字段接口
authFiledFilter.setSearchUserField("org_id");
authValidatorModel.setAuthFiledFilter(authFiledFilter);
AuthConfig.add(authValidatorModel);
}
}
上述初始化了权限校验的规则及关联字段,判断拥有角色user1及user2的能看到全部数据,其他要做过滤.
- 数据列表的mapper方法改造为如下:
<select id="list" resultMap="BaseResultMap">
select role.id,role.code,role.name
from sys_auth_role role
<if test="authModel != null">
${authModel.relSql}
</if>
where
1=1
<if test="authModel != null">
${authModel.condictionSql}
</if>
</select>
- 权限列表的生成authModel方法如下:
/**
* @description: 校验工具类
* @author: starmark
* @create: 2018-05-17 21:24
**/
public class AuthValidatorUtil {
public static AuthModel getAuthModel(String classModel, boolean isIn) {
AuthValidatorModel authValidatorModel = AuthConfig.get(classModel);
if (authValidatorModel == null) {
return null;
}
boolean isAuth = authValidatorModel.getRoles().stream().anyMatch(role -> UserUtil.containRole(role));
if (isAuth) {
return null;
}
AuthModel authModel = new AuthModel();
authModel.setRelSql(authValidatorModel.getAuthFiledFilter().getSqlRel());
if (isIn) {
authModel.setCondictionSql(authValidatorModel.getAuthFiledFilter().getCondictionSqlIn(UserUtil.getOrgIds()));
} else {
authModel.setCondictionSql(authValidatorModel.getAuthFiledFilter().getCondictionSqlEq(UserUtil.getUserId()));
}
return authModel;
}
}
上述该工具类用于做判断,看是否需要生成相关SQL
- 权限过滤调用的方法改写成如下:
/**
* 权限过滤查找相关角色
* @return
*/
public List<SysAuthRole> list(){
AuthModel authModel= AuthValidatorUtil.getAuthModel(SysAuthRole.class.getName(),true);
return authRoleMapper.list(authModel);
}
至此,我们列表权限过滤的架子已经搭建完成.
个人代码已经完成,如需要请打赏后通知我。谢谢.
如果你觉得该文章对你有帮助,麻烦点赞。
欢迎继续查看下篇文章-通用数据级别权限的框架设计与实现(4)-单条记录的权限控制