- 1. -关于@DataScope 注解的使用
-
** @DataScope**,我们系统设计上经常在做访问权限, 大部分是shiro 或者security等,但是数据权限之前很少用成熟的技术方案;
-
现阶段需要使用到 数据权限 结合着 访问权限 来做这个权限控制, 于是想起来了之前看到的一个写法,来源于 “若依”的一个aop注解 @DataScope;
-
两种业务逻辑 如果你们是 成熟的产品, 我建议你用第一种设计方案, 如果你们是定制化的产品, 我建议你做第二种方案;
3.1:成熟的设计方案,在sys_role表中新增data_scope 字段,用来表示当前角色的数据权限范围,
数据权限范围定义 //全部 public static final Integer DATA_SCOPE_ALL = 1; //自定义数据 public static final Integer DATA_SCOPE_CUSTOM = 2; //本部门 public static final Integer DATA_SCOPE_DEPT = 3; //本部门及部门一下 public static final Integer DATA_SCOPE_DEPT_AND_CHILD = 4; //个人 public static final Integer DATA_SCOPE_SELF = 5; //权限参数字段 public static final String DATA_SCOPE = "dataScope";
新增 数据库表字段如下图(图片转载于博主:渣渣成长之路)
@DataScope(deptAlias = "s",menuId = Constants.MENU_ID_ATTENDANCE_CARD)
public ApiResult query00001(){
//此处省略业务具体代码
}
自定义注解类
/**
* 数据权限过滤注解
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataScope {
/**
* 部门表的别名
*/
public String deptAlias() default "";
/**
* 用户表的别名
*/
public String userAlias() default "";
}
切面类DataScopeAspect
// 配置织入点
@Pointcut("@annotation(com.tacs.common.annotation.DataScope)")
public void dataScopePointCut() {
}
@Before("dataScopePointCut()")
public void doBefore(JoinPoint point) throws Throwable {
handleDataScope(point);
}
protected void handleDataScope(final JoinPoint joinPoint) {
// 获得注解
DataScope controllerDataScope = getAnnotationLog(joinPoint);
if (controllerDataScope == null) {
return;
}
// 获取当前的用户
UserDO user = 自定义获取用户信息方法;
if (!StringUtils.isEmpty(user)) {
// 如果是超级管理员,则不过滤数据
if (!StringUtils.isEmpty(user) && !user.getIsAdmin()) {
dataScopeFilter(joinPoint, user, controllerDataScope.deptAlias(), controllerDataScope.userAlias(), controllerDataScope.menuId());
}
}
}
/**
* 数据范围过滤
*
* @param joinPoint 切点
* @param user 用户
* @param userAlias 别名
*/
public void dataScopeFilter(JoinPoint joinPoint, UserDO user, String deptAlias, String userAlias, String menuId) {
//初始化数据权限参数值
Integer dataScope = 0;
//数据权限sql参数
StringBuilder sqlString = new StringBuilder();
// 获取当前登陆人所有角色
QueryWrapper<UserRoleDO> userRoleDOQueryWrapper = new QueryWrapper<>();
userRoleDOQueryWrapper.eq("user_id", user.getId());
List<UserRoleDO> userRols = userRoleMapper.selectList(userRoleDOQueryWrapper);
if (StringUtils.isEmpty(userRols)) {
log.info("获取当前登陆人角色信息失败,当前人员ID为:{},获取角色数据大小为:{}", user.getId(), userRols.size());
return;
}
QueryWrapper<SysRoleDataScope> sysRoleDataScopeQueryWrapper = new QueryWrapper<>();
for (SysRole role : user.getRoles())
{
String dataScope = role.getDataScope();
if (DATA_SCOPE_ALL.equals(dataScope))
{
sqlString = new StringBuilder();
break;
}
else if (DATA_SCOPE_CUSTOM.equals(dataScope))
{
sqlString.append(StringUtils.format(
" OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", deptAlias,
role.getRoleId()));
}
else if (DATA_SCOPE_DEPT.equals(dataScope))
{
sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", deptAlias, user.getDeptId()));
}
else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope))
{
sqlString.append(StringUtils.format(
" OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )",
deptAlias, user.getDeptId(), user.getDeptId()));
}
else if (DATA_SCOPE_SELF.equals(dataScope))
{
if (StringUtils.isNotBlank(userAlias))
{
sqlString.append(StringUtils.format(" OR {}.user_id = {} ", userAlias, user.getUserId()));
}
else
{
// 数据权限为仅本人且没有userAlias别名不查询任何数据
sqlString.append(" OR 1=0 ");
}
}
}
if (!StringUtils.isEmpty(sqlString.toString())) {
Object params = joinPoint.getArgs()[0];
if (!StringUtils.isEmpty(params) && params instanceof BasePageQuery) {
BasePageQuery basePageQuery = (BasePageQuery) params;
Map<String,Object> param = new HashMap<>();
param.put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")");
basePageQuery.setParams(param);
}
}
}
/**
* 是否存在注解,如果存在就获取
*/
private DataScope getAnnotationLog(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
if (method != null) {
return method.getAnnotation(DataScope.class);
}
return null;
}
Mapper.xml 通过${params.dataScope}来完成sql的拼接。params是实体类父类中的属性类型,类型为Map。从该属性中可以获取到需要拼接的sql。需要拼接的sql是在切面类中前置方法中存入的。(baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + “)”);)
SELECT
*
from
具体业务表
<!-- 数据范围过滤 -->
${params.dataScope}
order BY s.create_time DESC
注: 代码参考与博主 渣渣成长之路