本文剩下的最后一个问题是如何设置用户权限?今天我们就来聊聊这个话题。1.角色和权限首先,我们来看一下角色和权限。关于如何设计角色和权限其实有很多非常成熟的理论,最常见的就是RBAC。1.1RBAC简介RBAC(Role-basedaccesscontrol)是一种基于角色的访问控制(Role-basedaccesscontrol,RBAC)。是一种较新的、应用广泛的权限控制机制。这种机制不是直接给用户授予权限,而是给角色授予权限。RBAC权限模型按照角色对用户进行分类,通过用户的角色来判断用户是否具有对某个资源的操作权限。RBAC简化了用户和权限的管理。它将用户与角色、角色和权限以及权限与资源相关联。这种模型使得用户授权管理变得非常简单和易于维护。1.2RBAC提出的权限和角色可以在20世纪70年代初期商业计算机程序中的相关应用中找到,但是早期的程序比较简单,没有明确的、通用的、公认的权限管理模型。Ferraiolo和Kuhn在1992年提出了一种通用的基于角色的访问控制模型(这个模型好像比松哥还老),并首次提出了RBAC权限模型来替代传统的MAC和DAC。授权控制方案,并解释了RBAC中的相关概念。1992年提出的权限模型在1995年由Ferraiolo、Cugini和Kuhn进行了扩展。该模型的主要作用是所有访问都是通过角色进行的,而角色本质上是权限的集合,所有用户只能通过角色获得权限.在组织内部,角色相对稳定,而用户和权限众多且变化迅速。因此,通过角色控制权限可以简化访问控制的管理和检查。1996年,Sandhu、Coyne、Feinstein和Youman正式提出了RBAC模型,以模块化的方式对RBAC进行细化,并基于该理论提出了四种不同的模型RBAC0-RBAC3。如今,大多数信息技术供应商已将RBAC纳入其产品线。除了常规的企业级应用,RBAC还广泛应用于医疗、国防等领域。目前网上关于RBAC的理论性的东西只能找到英文的。有兴趣的朋友可以看看地址:https://csrc.nist.gov/projects/Role-Based-Access-Control各位大侠如果有中文资料的链接,请留言说明。1.3RBAC三原则最小权限:为角色配置的权限是完成任务所需的最小权限集合。职责分离:任务通过相互独立和相互排斥的角色共同完成。数据抽象:体现在权限的抽象上,RBAC支持的数据抽象程度与RBAC的实现细节有关。数据抽象:体现在权限的抽象上,RBAC支持的数据抽象程度与RBAC的实现细节有关。1.4RBAC模型分类1.4.1RBAC0RBAC0是最简单的用户、角色和权限模型。RBAC0是RBAC权限模型的核心部分,其他模型都是建立在这个基础上的。在RBAC0中,一个用户可以有多个角色,一个角色可以有多个权限,最终用户的权限是该用户拥有的角色权限的并集。1.4.2RBAC1RBAC1在RABC0的基础上引入了角色继承,允许角色之间存在上下级关系。在本系列的前几篇文章中,宋哥也多次为大家介绍了SpringSecurity中的角色继承。1.4.3RBAC2RBAC2也在RBAC0的基础上进行了扩展,引入了静态职责分离和动态职责分离。要理解职责分离,我们必须首先理解角色是相互排斥的。在实际项目中,有些角色是相互排斥、对立的。例如,财务的角色不能与其他角色结合。这个问题可以通过职责分离来解决:静态职责分离在设置阶段受到限制。例如,不能为同一个用户授予互斥的角色,一个用户只能拥有有限的几个角色,一个用户必须先有低级权限才能获得高级权限,等等。动态职责分离在运行时受到限制。例如,同一用户下的5个角色在运行时只能同时激活2个。1.4.4RBAC3将RBAC1和RBAC2组合成RBAC3。1.5扩展我们日常看到的很多权限模型都是在RBAC的基础上进行扩展的。比如在一些系统中,我们可以看到用户组的概念,就是把用户分组,用户同时有自己的角色和组角色。我们TienChin项目使用的脚手架中的权限基本都是基于RBAC权限模型。2.表的设计我们来看看若一-Vue脚手架中与用户、角色、权限相关的表。这里主要涉及到以下几个表:sys_user:这个是用户表。sys_role:这是角色表。sys_user_role:这是用户角色关联表。sys_menu:这是一个菜单表,也可以理解为资源表。sys_role_menu:这是资源角色关联表。通过用户id,可以去sys_user_role表查询该用户的角色id,然后根据角色id,去sys_role_menu表查询这个角色可以操作的资源id,然后根据resourceid,去sys_menu表中查询到对应的资源,基本上就是这么一个过程。那么如何在Java代码中做到这一点呢?3.代码实现首先定义了一个Java类SysUser,对应数据库中的sys_user表。我们看一下UserDetailsS??ervice的具体实现:@Autowired私有ISysUserService用户服务;@AutowiredprivateSysPermissionService权限服务;@OverridepublicUserDetailsloadUserByUsername(Stringusername)throwsUsernameNotFoundException{SysUseruser=userService.selectUserByUserName(用户名);if(StringUtils.isNull.log(user)){info("登录用户:{}不存在。",用户名);thrownewServiceException("登录用户:"+用户名+"不存在");}elseif(UserStatus.DELETED.getCode().equals(user.getDelFlag())){log.info("登录用户:{}已被删除。",用户名);thrownewServiceException("抱歉,您的账号:"+username+"已被删除");}elseif(UserStatus.DISABLE.getCode().equals(user.getStatus())){log.info("登录用户:{}已被停用。",用户名);thrownewServiceException("抱歉,您的账户:"+username+"已被停用");}返回createLoginUser(用户);}publicUserDetailscreateLoginUser(SysUseruser){returnnewLoginUser(user.getUserId(),user.getDeptId(),user,permissionService.getMenuPermission(user));}}queryfromdatabase我们得到的是SysUser对象,然后对该对象稍作修改,将其转化为LoginUser对象。这个LoginUser是UserDetails接口的实现类,里面存放的是当前登录用户的关键信息。在创建LoginUser对象时,有一个permissionService.getMenuPermission方法用于查询用户的权限。根据当前用户的id,查询用户的角色,再根据用户角色,查询用户的权限。此外,如果当前用户的角色是admin,则用户角色设置为*:*:*,这是硬编码的。我们再来看看LoginUser的设计:publicclassLoginUserimplementsUserDetails{/***permissionlist*/privateSet
