查看上篇文章通用数据级别权限的框架设计与实现(3)-数据列表的权限过滤,我们开始在原来的基础上实现单条权记录的权限控制。
相信前面的列表权限控制,很多系统都可以做到,但如何在上面列表的权限过滤中实现通用性
原理:我们在权限过滤中,通过AOP接截相关记录,拦截的时候,我们先判断当前人员是否有角色权限,没有的话,我们生成查询权限的SQL,进行权限查找.
1.先定义生成权限的相关注解,相关注解用于权限拦截,及获取拦截的相关参数.
Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AuthCheck {
/**权限校验规则
* @return
*/
Class classModel() ;
/**
* 判断是否IN查询
* @return
*/
boolean isIn() default true;
}
注解AuthCheck用于定义单条记录权限拦截的规则
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthParam {
}
AuthParam只是用于标记哪个参数用于权限校验.
2.生成权限校验SQL的类AuthFiledFilter修改
/**
* 生成对一条记录的权限校限SQL
* @param id
* @param valueList
* @return
*/
public String getAuthSqlIn(Object id, List valueList){
StringBuffer sb = new StringBuffer();
sb.append("select count(1) from ");
sb.append (this.getSalveTableName() );
sb.append(" where ").append(this.getSalveTableField()).append("=").append(id);
sb.append(" and ");
sb.append(this.buildLogicIN(this.getSearchUserField(), valueList));
return sb.toString();
}
/**
* 生成对一条记录的权限校验SQL,用EQ
* @param id
* @param userId
* @return
*/
public String getAuthSqlEq(Object id,Object userId){
StringBuffer sb = new StringBuffer();
sb.append("select count(1) from ");
sb.append (this.getSalveTableName() );
sb.append(" where ").append(this.getSalveTableField()).append("=").append(id);
sb.append(" and ");
sb.append( this.getSearchUserField()).append("=").append(userId);
return sb.toString();
}
3.权限拦截判断的类AuthValidatorUtil的规则增加
//生成校验的
public static String getAuthModelSql(String classModel, Object id,boolean isIn) {
AuthValidatorModel authValidatorModel = AuthConfig.get(classModel);
if (authValidatorModel == null) {
return "";
}
boolean isAuth = authValidatorModel.getRoles().stream().anyMatch(role -> UserUtil.containRole(role));
if (isAuth) {
return "";
}
String checkAuthSql="";
if (isIn) {
checkAuthSql = authValidatorModel.getAuthFiledFilter().getAuthSqlIn(id, UserUtil.getOrgIds());
} else {
checkAuthSql = authValidatorModel.getAuthFiledFilter().getAuthSqlEq(id, UserUtil.getUserId());
}
return checkAuthSql;
}
4.关键对有权限标识注解的权限拦截
@Aspect
@Order(1)
@Component
public class AuchCheckAspect {
protected final Log logger = LogFactory.getLog(AuchCheckAspect.class);
@Autowired
AuthMapper authMapper;
/**
* 权限校验
*
* @param joinPoint
* @throws Throwable
*/
@Before(value = "@annotation( com.starmark.auth.anno.AuthCheck)")
public void timeAroundAdvice(JoinPoint joinPoint) throws Throwable {
//相关参数
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
AuthCheck AuthCheck = method.getAnnotation(AuthCheck.class);
String classModel = AuthCheck.classModel().getName();
Assert.notNull(classModel, " 权限校验模型不允许为空");
Object id = null;
Object[] args = joinPoint.getArgs();
//从方法中获取相关主键校验参数
Parameter[] parameters = method.getParameters();
for (int i = 0; i < parameters.length; i++) {
AuthParam authParam = parameters[i].getAnnotation(AuthParam.class);
if (authParam != null) {
id = args[i];
break;
}
}
AuthValidatorModel authValidatorModel = AuthConfig.get(classModel);
String checkAuthSql = AuthValidatorUtil.getAuthModelSql(classModel,id,AuthCheck.isIn());
if (StringUtils.isNotEmpty(checkAuthSql)) {
boolean isAuth = authMapper.isAuth(checkAuthSql);
if (!isAuth) {
throw new AuthCheckException();
}
}
}
}
这里提示一下,AuthMapper是我们执行一条生成的SQL方法,是注入一条SQL,因为SQL是我们后台代码生成的,无须考虑SQL注入的问题
5.相关权限的功能使用
@GetMapping(value = "/{id}")
@AuthCheck(classModel = SysAuthRole.class)
public Object get(@PathVariable("id") @AuthParam Long id) {
return sysAuthRoleService.get(id);
}
6.测试:
打开有权限的记录,正常结果如下:
打开没有权限的记录,抛出一个无权限的异常。
至此,单条记录的权限拦截已完成!
个人代码已经完成,如需要请打赏后通知我。谢谢.
如果你觉得该文章对你有帮助,麻烦点赞。
欢迎继续查看下篇文章-通用数据级别权限的框架设计与实现(5)-总结与延伸思考