赞
踩
RBAC模型包含的表有下面五张:
1. 用户表
2. 角色表
3. 权限菜单表
4. 用户和角色的关联表
5. 角色和权限菜单的关联表
关系如下:

具体代码如下:
controller层:SysLoginController下的getRouters()方法
/**
* 获取路由信息
*
* @return 路由信息
*/
@GetMapping("getRouters")
public AjaxResult getRouters()
{
Long userId = SecurityUtils.getUserId();
List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
return AjaxResult.success(menuService.buildMenus(menus));
}
service层:SysMenuServiceImpl下的selectMenuTreeByUserId()方法
/** * 根据用户ID查询菜单 * * @param userId 用户名称 * @return 菜单列表 */ @Override public List<SysMenu> selectMenuTreeByUserId(Long userId) { List<SysMenu> menus = null; if (SecurityUtils.isAdmin(userId)) { menus = menuMapper.selectMenuTreeAll(); } else { menus = menuMapper.selectMenuTreeByUserId(userId); } return getChildPerms(menus, 0); }
先判断用户是否为超级管理员,若是,则返回所有权限菜单,若不是,则根据用户id返回菜单
mapper层:SysMenuMapper
超级管理员执行的sql
/**
* 根据用户ID查询菜单
*
* @return 菜单列表
*/
public List<SysMenu> selectMenuTreeAll();
<select id="selectMenuTreeAll" resultMap="SysMenuResult">
select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.component, m.`query`, m.visible, m.status, ifnull(m.perms,'') as perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time
from sys_menu m where m.menu_type in ('M', 'C') and m.status = 0
order by m.parent_id, m.order_num
</select>
其他用户执行的sql
/**
* 根据用户ID查询菜单
*
* @param userId 用户ID
* @return 菜单列表
*/
public List<SysMenu> selectMenuTreeByUserId(Long userId);
<select id="selectMenuListByUserId" parameterType="SysMenu" resultMap="SysMenuResult"> select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.component, m.`query`, m.visible, m.status, ifnull(m.perms,'') as perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time from sys_menu m left join sys_role_menu rm on m.menu_id = rm.menu_id left join sys_user_role ur on rm.role_id = ur.role_id left join sys_role ro on ur.role_id = ro.role_id where ur.user_id = #{params.userId} <if test="menuName != null and menuName != ''"> AND m.menu_name like concat('%', #{menuName}, '%') </if> <if test="visible != null and visible != ''"> AND m.visible = #{visible} </if> <if test="status != null and status != ''"> AND m.status = #{status} </if> order by m.parent_id, m.order_num </select>
以获取用户列表的接口为例
/**
* 获取用户列表
*/
@PreAuthorize("@ss.hasPermi('system:user:list')")
@GetMapping("/list")
public TableDataInfo list(SysUser user)
{
startPage();
List<SysUser> list = userService.selectUserList(user);
return getDataTable(list);
}
接口权限是基于SpringSecurity的注解@PreAuthorize实现的
若依框架在PermissionService中重新定义了hasPermi()方法
/** * RuoYi首创 自定义权限实现,ss取自SpringSecurity首字母 * * @author ruoyi */ @Service("ss") public class PermissionService { . . . /** * 验证用户是否具备某权限 * * @param permission 权限字符串 * @return 用户是否具备某权限 */ public boolean hasPermi(String permission) { if (StringUtils.isEmpty(permission)) { return false; } LoginUser loginUser = SecurityUtils.getLoginUser(); if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions())) { return false; } PermissionContextHolder.setContext(permission); return hasPermissions(loginUser.getPermissions(), permission); } . . . }
每次带有注解@PreAuthorize的请求过来,就会先执行hasPermi(),判断是否具备某权限,若返回false则没有权限,若返回true,则有权限,可以执行该接口
数据权限的核心就是使用aop切面,拼接sql语句

这里的dataScope参数通过实行切面传入
在service层里添加注解@DataScope,这是若依框架中的一个自定义注解

通过监听这个注解来执行切面,DataScopeAspect为定义切面的类
这里的基本思想就是把要拼接的sql语句传到基类中的params里,params是BaseEntity类中的一个map类型的属性

这里第一步是清空params里面的dataScope,然后再判断其是否具有权限,再把拼接后的sql语句放到params里的dataScope里面
/**
* 拼接权限sql前先清空params.dataScope参数防止注入
*/
private void clearDataScope(final JoinPoint joinPoint)
{
Object params = joinPoint.getArgs()[0];
if (StringUtils.isNotNull(params) && params instanceof BaseEntity)
{
BaseEntity baseEntity = (BaseEntity) params;
baseEntity.getParams().put(DATA_SCOPE, "");
}
}
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); } } }
数据权限分为五种,分别是全部数据权限、自定数据权限、部门数据权限、部门及以下数据权限、仅本人数据权限,拼接对应的sql语句


最后将拼接好后的sql语句放到params.dataScope里面

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。