1. RBAC模型
现有业务系统都要用到用户权限功能,其中的理论基础就是RBAC(Role-Based Access Control)即:基于角色的权限控制。通过角色关联用户,角色关联权限的方式间接赋予用户权限。
RBAC模型可以分为:RBAC0、RBAC1、RBAC2、RBAC3 四种。其中RBAC0是基础,也是最简单的,相当于底层逻辑,RBAC1、RBAC2、RBAC3都是以RBAC0为基础的升级。
- RBAC0 :最简单的用户、角色、权限模型 ;
- RBAC1: 相对于RBAC0模型,增加了子角色,引入了继承概念,即子角色可以继承父角色的所有权限
- RBAC2: 基于RBAC0模型,增加了对角色的一些限制:角色互斥、基数约束、先决条件角色等。
- RBAC3: 就是前面几种情况的合集,一般只有在非常复杂的系统中才会用到。
2. 常见权限数据库模型
- 其中用户与角色是多对多,角色与菜单权限是多对多。
- 角色与部门是多对多,主要是为了按此角色可以访问哪些部门的数据权限,通过此动态注入相关 sql,到达动态过滤效果。
比较复杂是的数据权限的实现,具体实现过程如下:
a.定义数据过滤注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataFilter {
/** 表的别名 */
String tableAlias() default "";
/** true:没有本部门数据权限,也能查询本人数据 */
boolean user() default true;
/** true:拥有子部门数据权限 */
boolean subDept() default false;
/** 部门ID */
String deptId() default "dept_id";
/** 用户ID */
String userId() default "user_id";
}
b.动态SQL拦截注入
@Aspect
@Component
public class DataFilterAspect {
@Autowired
private SysDeptService sysDeptService;
@Autowired
private SysUserRoleService sysUserRoleService;
@Autowired
private SysRoleDeptService sysRoleDeptService;
@Pointcut("@annotation(com.xb.common.annotation.DataFilter)")
public void dataFilterCut() {
}
@Before("dataFilterCut()")
public void dataFilter(JoinPoint point) throws Throwable {
Object params = point.getArgs()[0];
if(params != null && params instanceof Map){
SysUserEntity user = ShiroUtils.getUserEntity();
//如果不是超级管理员,则进行数据过滤
if(user.getUserId() != Constant.SUPER_ADMIN){
Map map = (Map)params;
map.put(Constant.SQL_FILTER, getSQLFilter(user, point));
}
return ;
}
throw new RRException("数据权限接口,只能是Map类型参数,且不能为NULL");
}
/**
* 获取数据过滤的SQL
*/
private String getSQLFilter(SysUserEntity user, JoinPoint point){
MethodSignature signature = (MethodSignature) point.getSignature();
DataFilter dataFilter = signature.getMethod().getAnnotation(DataFilter.class);
//获取表的别名
String tableAlias = dataFilter.tableAlias();
if(StringUtils.isNotBlank(tableAlias)){
tableAlias += ".";
}
//部门ID列表
Set<Long> deptIdList = new HashSet<>();
//用户角色对应的部门ID列表
List<Long> roleIdList = sysUserRoleService.queryRoleIdList(user.getUserId());
if(roleIdList.size() > 0){
List<Long> userDeptIdList = sysRoleDeptService.queryDeptIdList(roleIdList.toArray(new Long[roleIdList.size()]));
deptIdList.addAll(userDeptIdList);
}
//用户子部门ID列表
if(dataFilter.subDept()){
List<Long> subDeptIdList = sysDeptService.getSubDeptIdList(user.getDeptId());
deptIdList.addAll(subDeptIdList);
}
StringBuilder sqlFilter = new StringBuilder();
sqlFilter.append(" (");
if(deptIdList.size() > 0){
sqlFilter.append(tableAlias).append(dataFilter.deptId()).append(" in(").append(StringUtils.join(deptIdList, ",")).append(")");
}
//没有本部门数据权限,也能查询本人数据
if(dataFilter.user()){
if(deptIdList.size() > 0){
sqlFilter.append(" or ");
}
sqlFilter.append(tableAlias).append(dataFilter.userId()).append("=").append(user.getUserId());
}
sqlFilter.append(")");
if(sqlFilter.toString().trim().equals("()")){
return null;
}
return sqlFilter.toString();
}
}
c.service方法使用示例
@DataFilter(subDept = true, user = false, tableAlias = "t1")
public List<SysDeptEntity> queryList(Map<String, Object> params){
return baseMapper.queryList(params);
}
d.动态加入sql_fliter
<select id="queryList" resultType="com.xb.modules.sys.entity.SysDeptEntity">
select t1.*,(select t2.name from sys_dept t2 where t2.dept_id=t1.parent_id)parentName from sys_dept t1 where
t1.del_flag = 0
<if test="sql_filter != null">
and ${sql_filter}
</if>
</select>
3. shiro 介绍
Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。
- Authentication(认证):用户身份识别,通常被称为用户“登录”
- Authorization(授权):访问控制。比如某个用户是否具有某个操作的使用权限。
- Session Management(会话管理):特定于用户的会话管理,甚至在非web 或 EJB 应用程序。
- Cryptography(加密):在对数据源使用加密算法加密的同时,保证易于使用。
Shiro 架构包含三个主要的理念:Subject,SecurityManager和 Realm。下面的图展示了这些组件如何相互作用,我们将在下面依次对其进行描述。
4. shiro 权限控制
Shiro 进行权限控制
四种主要方式 :
a、 在程序中 通过 Subject 编程方式进行权限控制,不常用。
b、 配置 Filter 实现 URL 级别粗粒度权限控制
- xxx.html* = anon (未登录可以访问)
- xxx.html* =authc (必须登录才能访问 )
- xxx.html* = perms[权限] (需要特定权限才能访问)
- xxx.html* = roles[角色] (需要特定角色才能访问 )
c、 配置代理,基于注解实现细粒度权限控制
- @RequiresPermissions(权限) 需要特定权限才能访问
- @RequiresRoles(角色) 需要特定角色才能访问
- @RequiresAuthentication 需要认证才能访问
d、 在页面中使用 shiro 自定义标签实现 页面显示权限控制
- <shiro:authenticated> 登录后才能访问
- <shiro:hasPermission name="abc"> 需要特定权限才能访问
- <shiro:hasRole name="abc"> 需要特定角色才能访问
参考: https://gitee.com/pengchua/webframework_merge/tree/master/web-framework/xb-admin
来源:oschina
链接:https://my.oschina.net/pengchanghua/blog/4288478