口断开表与表层面的关联,另辟蹊径从其他角度找到方式进行关联。这里我们主要采取了shiro的自定义注解的方案。本篇文章主要解决以下的问题。
如何通过逻辑进行页面与api接口的关联。
shiro的自身注解的用法。
如何编写自定义注解。
如何通过逻辑进行页面与api接口的关联
在表与表的结构关系中,页面和接口表最终都是与权限表进行的关联(详情请查看我的上一篇文章《权限设计的杂谈》)。
中1.jpg
我们现在希望用另一种方案去替代他,实现一个低成本同时兼顾一定程度的权限控制。这里我们引入两个概念。业务模块,操作类型。
业务模块
概念:将系统中的业务模块抽象成一种数据,我们可以用字符串的形式去表示,例如:角色管理对应是role-manage、用户管理对应是user-manage等等。我们将系统中所存在的业务模块通过“最小特权原则”进行划分,最终形成一批可分配的数据。
使用原则:api接口和页面以及功能从本质上来说,都和业务模块有逻辑关系,于是,我们可以对api接口与页面(以及功能点)进行逻辑匹配,来判断页面与接口的关系。
操作类型
概念:将系统中的所有的操作类型抽象成一种数据,我们也可以用字符串的形式去表示,例如:新增对应的是add、分配对应的是allot等等。我们将系统中所有的操作类型根据业务模块通过“数据许可证”进行划分,最终形成一批可分配的数据。
使用原则:页面是展示,功能点是动作,而接口是最终动作的资源提供,通过“业务模块”确定了调取的资源,通过“操作类型”确定了资源的使用方式。通过两者可以大致无误的判断页面的功能点触发的接口是否在鉴权之内。
现在提出了这两个概念,他们最终的实际的使用方式是什么,我们先从以下几个角度去思考一下。
1、数据库中的页面表或的api接口表中的数据就是真实有效吗?
2、页面或接口的实际使用,是以功能存在为前提,还是以数据库表中的数据存在为前提。
3、权限结构中,“控制对象”的存储只有数据库这一种途径吗?
我们从结论出发来看这几个问题,首先“控制对象”的存储除了在数据库中也可以代码中,也可以在配置文件中,并不一定非得在数据库;那么接着回答第二个问题,当数据库存在的接口信息,而服务端并没有开发这个接口的时候,数据库的信本身就有问题,亦或者,数据库里新增的接口必定是服务端上已经部署的接口才能生效;接着就是第一个问题,那么数据库中关于“控制对象”的表中的数据并不一定是真实有效的。所以我们可以得出以下的解决方案
1、我们可以在接口上用注解的形式补充“业务模块”和“操作类型”的数据信息,这两类信息都可以存于常量类中,
2、在数据库添加创建页面表结构和页面功能表结构的时候,添加“业务模块”和“操作类型”字段。
3、可以将“业务模块”和“操作类型”的信息存于数据库的字典表中。
4、模块的新增或操作的新增,必定带来了接口的新增,那么就会带来一次系统部署活动,这个运维成本是无法减少的,并不能通过表结构来减少。
中2.png
但是这种方案仅适用于非强控制接口型的项目,在强控制型的接口项目仍然要将页面与接口进行绑定,虽然这会带来巨大的运维成本。另外也可以通过接口路由规则进行划分,例如:/api/page/xxxx/(仅对页面使用),/api/mobile/xxxxx(仅对移动端使用)将仅供页面使用的接口进行分类,这类接口仅做认证不做授权,也可以达到目的。
shiro的自身注解的用法
通过一个理论上的思路认可之后,剩下的则是付诸技术上的实践,我们这边采用的是Apache Shiro的安全框架,在Spring Boot的环境下应用。简要说明以下几个shiro的注解。
中3.png
/** * 1.当前接口需要经过"认证"过程 * @return */ @RequestMapping(value = "/info",method = RequestMethod.GET) @RequiresAuthentication public String test(){ return "恭喜你,拿到了参数信息"; } /** * 2.1.当前接口需要经过权限校验(需包含 角色的查询 或 菜单的查询) * @return */ @RequestMapping(value = "/info",method = RequestMethod.GET) @RequiresPermissions(value={"role:search","menu":"search"},logical=Logical.OR) public String test(){ return "恭喜你,拿到了参数信息"; } /** * 2.2.当前接口需要经过权限校验(需包含 角色的查询 与 菜单的查询) * @return */ @RequestMapping(value = "/info",method = RequestMethod.GET) @RequiresPermissions(value={"role:search","menu":"search"},logical=Logical.OR) public String test(){ return "恭喜你,拿到了参数信息"; } /** * 3.1.当前接口需要经过角色校验(需包含admin的角色) * @return */ @RequestMapping(value = "/info",method = RequestMethod.GET) @RequiresRoles(value={"admin"}) public String test(){ return "恭喜你,拿到了参数信息"; } /** * 3.2.当前接口需要经过角色与权限的校验(需包含admin的角色,以及角色的查询 或 菜单的查询) * @return */ @RequestMapping(value = "/info",method = RequestMethod.GET) @RequiresRoles(value={"admin"}) @RequiresPermissions(value={"role:search","menu":"search"},logical=Logical.OR) public String test(){ return "恭喜你,拿到了参数信息"; }
作者:小红牛
链接:https://www.jianshu.com/p/37bd96e3f548
共同學習,寫下你的評論
評論加載中...
作者其他優(yōu)質文章