每个系统都有权限设计,本篇主要将初始的权限设计的原理,不依赖任何框架,以直观的角度剖析web的权限设计。
权限设计的原理知识
什么是权限管理
只要有用户参与的系统一般都有权限管理,权限管理实现对用户访问系统的控制。按照安全规则或者安全策略控制用户可以访问而且只能访问自己被授权的资源。
权限管理包括用户认证和用户授权两部分。
用户认证
概念
用户认证-----用户访问系统,系统需要验证用户身份的合法性。常用的验证方法:1.用户名密码验证。2.指纹验证。3.证书验证。系统验证用户身份合法,用户才可以访问资源。
用户认证的流程
关键对象
subject :主体,理解为用户,可能是程序,都要去访问系统的资源,系统需要对subject进行身份验证。
principal :身份信息,通常是唯一的,一个主题可以有多个身份信息,但是只能有一个主身份信息(primary principal)。
credential :凭证信息,可以是密码,证书,指纹等。
主体在进行身份认证时需要提供身份信息和凭证信息。
用户授权
概念
用户授权,简单理解为访问控制,在用户认证通过后,系统对用户访问资源进行控制,当用户具有资源的访问权限方可访问。
授权流程
关键对象
授权的过程可以理解为 who 对 what(which)进行how操作
who : 主体,即subject,subject在认证通过后,系统可以进行访问控制。
what(which): 资源(Resource),subject必须具备资源访问权限才可以访问改权限。资源包括很多方面,比如:用户列表页面,商品修改菜单等。资源分为资源类型和资源实例:
例如系统的用户信息就是资源类型,相当于java类。
系统中id为1的用户就是资源实例,相当于java对象。
how : 权限(permission),针对资源的权限或许可,subject必须具有permission方可访问资源,如何访问/操作需要定义permission,权限比如:用户添加,修改,删除等。
权限模型
主体(账号、密码)
资源(资源名称、访问地址)
权限(权限名称、资源id)
角色(角色名称)
角色和权限的关系,用户和角色的关系。
如下图:
通常企业开发中将资源和权限合并成一张权限表,如下:
资源(资源名称,访问地址)
权限(权限名称,资源id)
合并为:
权限(权限名称,资源名称,资源访问地址)
上图是权限管理的通用模型,当然在实际开发中也可以根据自己的需要修改。
分配权限
用户需要分配相应的权限才可以访问相应的资源。权限是对资源的操作许可。
通常给用户分配资源权限需要将权限信息持久化,比如存储到关系数据库中。
把用户信息,权限管理,角色信息写入数据库中。
基于角色的访问控制
RBAC(role based access control),基于角色的访问控制。
比如:
系统角色包括 :部门经理、总经理。。(角色针对用户来划分)
系统代码中实现:
//如果该user是部门经理则可以访问if中的代码
if(user.hasRole('部门经理')){
//系统资源内容
//用户报表查看
}
问题:
角色针对人划分的,人作为用户在系统中属于活动内容,如果该 角色可以访问的资源出现变更,需要修改你的代码了,比如:需要变更为部门经理和总经理都可以进行用户报表查看,代码改为:
if(user.hasRole('部门经理') || user.hasRole('总经理') ){
//系统资源内容
//用户报表查看
}
基于角色的访问控制是不利于系统维护(可扩展性不强)。
基于资源的访问控制
RBAC(Resource based access control),基于资源的访问控制。
资源在系统中是不变的,比如资源有:类中的方法,页面中的按钮等。
对资源的访问需要具有permission权限,代码可以写成:
if(user.hasPermission ('用户报表查看(权限标识符)')){
//系统资源内容
//用户报表查看
}
上边的方法就可以解决用户角色变更不用修改上边权限控制的代码。
如果需要变更权限只需要在分配权限模块去操作,给部门经理或总经理增或删除权限。
建议使用基于资源的访问控制实现权限管理。
权限管理解决方案
粗粒度和细粒度权限
粗粒度权限管理,对资源类型的权限管理。资源类型比如:菜单,url连接,用户添加页面,用户信息,类方法,页面按钮。
粗粒度权限管理比如:超级管理员可以访问用户添加页面,用户信息等全部页面。
部门管理员可以访问用户信息页面,包括页面中的按钮。
细粒度权限管理,对资源实例的权限管理。资源实例就是资源类型的具体化,比如:行政部门的员工,id为1的用户的查看页面等。
细粒度权限管理就是数据级别的权限管理
细粒度权限管理比如:部门经理只可以访问本部门的员工信息,用户只可以看到自己的菜单,大区经理只能查看本辖区的销售订单。。
粗粒度和细粒度例子:
系统有一个用户列表查询页面,对用户列表查询分权限,如果粗颗粒管理,张三和李四都有用户列表查询的权限,张三和李四都可以访问用户列表查询。
进一步进行细颗粒管理,张三(行政部)和李四(开发部)只可以查询自己本部门的用户信息。张三只能查看行政部 的用户信息,李四只能查看开发部门的用户信息。
如何实现粗粒度和细粒度权限管理
如何实现粗粒度权限管理?
粗粒度权限管理比较容易将权限管理的代码抽取出来在系统架构级别统一处理。比如:通过springmvc的拦截器实现授权。
如何实现细粒度权限管理?
对细粒度权限管理在数据级别是没有共性可言,针对细粒度权限管理就是系统业务逻辑的一部分,如果在业务层去处理相对比较简单,如果将细粒度权限管理统一在系统架构级别去抽取,比较困难,即使抽取的功能可能也存在扩展不强。
建议细粒度权限管理在业务层去控制。
比如:部门经理只查询本部门员工信息,在service接口提供一个部门id的参数,controller中根据当前用户的信息得到该 用户属于哪个部门,调用service时将部门id传入service,实现该用户只查询本部门的员工。
基于url拦截的方式实现
基于url拦截的方式实现在实际开发中比较常用的一种方式。
对于web系统,通过filter过虑器实现url拦截,也可以springmvc的拦截器实现基于url的拦截。
基于权限框架的方式实现
对于粗粒度权限管理,建议使用优秀权限管理框架来实现,节省开发成功,提高开发效率。
shiro就是一个优秀权限管理框架。
基于url的权限管理
基于url的权限管理流程
搭建环境
数据库
mysql数据库中创建表:用户表、角色表、权限表(实质上是权限和资源的结合 )、用户角色表、角色权限表。
创建好的表如下:
shiro_sql_table.sql:
CREATE TABLE `sys_permission` (
`id` bigint(20) NOT NULL COMMENT '主键',
`name` varchar(128) NOT NULL COMMENT '资源名称',
`type` varchar(32) NOT NULL COMMENT '资源类型:menu,button,',
`url` varchar(128) DEFAULT NULL COMMENT '访问url地址',
`percode` varchar(128) DEFAULT NULL COMMENT '权限代码字符串',
`parentid` bigint(20) DEFAULT NULL COMMENT '父结点id',
`parentids` varchar(128) DEFAULT NULL COMMENT '父结点id列表串',
`sortstring` varchar(128) DEFAULT NULL COMMENT '排序号',
`available` char(1) DEFAULT NULL COMMENT '是否可用,1:可用,0不可用',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*Table structure for table `sys_role` */
CREATE TABLE `sys_role` (
`id` varchar(36) NOT NULL,
`name` varchar(128) NOT NULL,
`available` char(1) DEFAULT NULL COMMENT '是否可用,1:可用,0不可用',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*Table structure for table `sys_role_permission` */
CREATE TABLE `sys_role_permission` (
`id` varchar(36) NOT NULL,
`sys_role_id` varchar(32) NOT NULL COMMENT '角色id',
`sys_permission_id` varchar(32) NO