目录
不同权限思维导图图
后端源码解析
Controller
1.前端发送请求,后端接收get,里面做的是分页需要继续深入selectUserList才能看到对应的修改。
@RestController
@RequestMapping("/system/user")
public class SysUserController extends BaseController
{
......
@GetMapping("/list")
public TableDataInfo list(SysUser user)
{
startPage();
List<SysUser> list = userService.selectUserList(user);
return getDataTable(list);
}
.....
}
DataScope
在selectUserList中有注解DataScope
注意
1.部门别名和用户别名用在SQL 语句中,
2.需要跟SQL 语句给部门和用户表名的别名保持一致
@Service
public class SysUserServiceImpl implements ISysUserService
{
......
@Override
@DataScope(deptAlias = "d", userAlias = "u")
public List<SysUser> selectUserList(SysUser user)
{
return userMapper.selectUserList(user);
}
......
}
注解@DataScope 定义
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataScope
{
/**
* 部门表的别名
*/
public String deptAlias() default "";
/**
* 用户表的别名
*/
public String userAlias() default "";
/**
* 权限字符(用于多个角色匹配符合要求的权限)默认根据权限注解@ss获取,多个权限用逗号分隔开来
*/
public String permission() default "";
}
AOP 类DataScopeAspect
注意:加上注解@DataScope的函数要被执行时,先执行doBefore,这里相当于前面的selectUserList在执行时被doBefore拦截,先执行了doBefore里的语句再执行加上注解@DataScope的函数
@Aspect
@Component
public class DataScopeAspect
{
......
@Before("@annotation(controllerDataScope)")
public void doBefore(JoinPoint point, DataScope controllerDataScope) throws Throwable
{
clearDataScope(point);
handleDataScope(point, controllerDataScope);
}
......
}
handleDataScope
doBefore继续进入函数handleDataScope,这里会获取当前登录的用户,然后通过dataScopeFilter函数来组件对应XML里的${params.dataScope}
if(条件是不为空并且不为管理员):管理员不需要加过滤数据,不为Admin则进入if中进入dataScopeFilter
protected void handleDataScope(final JoinPoint joinPoint, DataScope controllerDataScope)
{
// 获取当前的用户
LoginUser loginUser = SecurityUtils.getLoginUser();
if (StringUtils.isNotNull(loginUser))
{
SysUser currentUser = loginUser.getUser();
// 如果是超级管理员,则不过滤数据
if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin())
{
String permission = StringUtils.defaultIfEmpty(controllerDataScope.permission(), PermissionContextHolder.getContext());
dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(),
controllerDataScope.userAlias(), permission);
}
}
}
dataScopeFilter
DATA_SCOPE_DEPT.equals(dataScope)
在其中dataScope是满足本部门数据权限就会给DATA_SCOPE_DEPT常量赋值,对应值1-5
这里因为有有测试3中情况但超级管理员不传入函数所以DATA_SCOPE_DEPT会是3和5两种
等效与1:自定义权限(OR {}.dept_id = {} ", deptAlias, user.getDeptId()) = OR d.dept_id = 105。(自定义权限跟部门表有关,需要通过dept_id去找,SQL返回部门全部数据)
2:本人权限(OR {}.user_id = {} ", userAlias, user.getUserId() = OR u.user_id = 用户的编码(本人权限只有找到自己的user_id返回,这里提供humou的例子u.user_id被改为100,SQL只能返回自己这条数据)
public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias, String permission)
{
......
else if (DATA_SCOPE_DEPT.equals(dataScope))
{
sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", deptAlias, 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(StringUtils.format(" OR {}.dept_id = 0 ", deptAlias));
}
}
......
if (StringUtils.isNotBlank(sqlString.toString()))
{
Object params = joinPoint.getArgs()[0];
if (StringUtils.isNotNull(params) && params instanceof BaseEntity)
{
BaseEntity baseEntity = (BaseEntity) params;
baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")");
}
}
}
这里就是对应的XML里的sql语句,然后会根据dataScopeFilter函数组装的AND + sql语句赋值给${params.dataScope},通过查询的的结果返回给前端List
<select id="selectUserList" parameterType="SysUser" resultMap="SysUserResult">
select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, d.dept_name, d.leader from sys_user u
left join sys_dept d on u.dept_id = d.dept_id
where u.del_flag = '0'
<if test="userId != null and userId != 0">
AND u.user_id = #{userId}
</if>
<if test="userName != null and userName != ''">
AND u.user_name like concat('%', #{userName}, '%')
</if>
<if test="status != null and status != ''">
AND u.status = #{status}
</if>
<if test="phonenumber != null and phonenumber != ''">
AND u.phonenumber like concat('%', #{phonenumber}, '%')
</if>
<if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 -->
AND date_format(u.create_time,'%y%m%d') >= date_format(#{params.beginTime},'%y%m%d')
</if>
<if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
AND date_format(u.create_time,'%y%m%d') <= date_format(#{params.endTime},'%y%m%d')
</if>
<if test="deptId != null and deptId != 0">
AND (u.dept_id = #{deptId} OR u.dept_id IN ( SELECT t.dept_id FROM sys_dept t WHERE find_in_set(#{deptId}, ancestors) ))
</if>
<!-- 数据范围过滤 -->
${params.dataScope}
</select>
前端展示效果
这里新建两个用户(一个为普通员工(本人数据权限),一个为项目负责人(自定义数据权限))
超级管理员对应的sql查询 where是没有做任何的其他条件
注意若输入框如(用户名称,手机号码,状态等都为空)否则XML里也是会对where进行附加条件的。
两个角色都是财务部,自定义数据权限这里给与财务部权限
普通员工就只有本人权限
使用humoumou登录可以看到财务部门的全部用户,但ry用户因为不是同一个部门所以看不到
d.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = 3 ) 找的是测试部门的id,select返回测试部门的所以数据
使用humou登录因为是本人权限前端只展示有自己一个人
本人数据全选对应的sql条件也就是找user里找到对应人员的id