安全管理是最复杂也是最难以理解的功能模块,理论上仅对系统管理员开放该功能。总的来看安全管理主要分为用户管理、用户权限、角色来分派权限。
在介绍安全管理之前,先让我们对一些关键字有所了解。
关键词:
ü
用户:权限的持有者。一般来说通过登录账号对应客观世界的一个人,一个用户有且只能在一个部门下。用户在权限系统中又分为不同的类型:一般用户/超级管理员(不受权限限制,在应用系统中有无限的权力)
ü
权限:一个权限对应一个功能,这个功能可以是页面/页面中的表单元素(如按钮/文本框)/业务层的方法,在技术层面看,一个权限只是一个字符串。目的是用户拥有的权限与功能的配置权限做匹配,以达到权限验证效果
ü
角色:权限的集合,因为权限的颗粒度太小无法满足对一个完整业务授权管理的描述。如会计角色,要求可以增加、删除与修改会计科目(或更多),而增加或删除会计科目均是一个功能单元应分别对应各自的权限。在应用系统中,一个角色实际上就是一个工作职能所拥有的权限集合。
ü
组织结构:是用户与部门的总称。部门应是树形结构。之所以在权限管理中引用组织结构,是因为影响权限对数据的筛选范围。对于范围可以分为:用户级(当前用户自己创建的记录)/系统级(所有记录)/当前部门级(当前用户所在的部门中所有用户创建的记录)/部门级/部门及子部门级。对于后两种类型还需要授权时给出参考部门。
操作方案:
方案1. 将多个权限直截分派给用户
方案2. 将多个权限合并为一个角色,再将多个角色分派给用户
此两种方案是按系统复杂程度逐级递增的,从权限的维护难度来看也是逐级递增。在此要注意,在一个应用系统中您只能选择两种方案其中的一种来维护您的权限管理,强烈不推荐多种方案在同一个应用系统中同时管理的情况出现。这样会导致后期系统维护的混乱,严重时有可能产生系统瘫痪!
通过用操作:
在分派某些查询权限时页面中会显示范围与部门
在范围中只有部门级与部门及子部门极,部门一列才会显示。权限控制范围(以订单为例)如下:
²
用户级:只能看到当前用户自己所创建的订单
²
当前部门级:如果当前用户与订单的创建人在同一个部门,则当前用户在查询订单时可以看到该订单
²
部门级:可以为当前用户指定一个部门,使他只能看到这个部门下所有员工所创建的订单
²
部门及子部门级:可以为当前用户指定一个部门,使他可以能看到这个部门包括这个部门下所有的子孙部门中所有员工所创建的订单(部门或者说是组织结构应是树形结构)
²
系统级:能看到所有订单不受到任何组织结构及创建人的限制
用户管理:
提供系统管理员对企业内与企业外用户的安全认证管理。虽然在此处提供删除用户的功能,但不推荐使用。一般来说无论是新增还是删除员工、客户联系人都应是人力资源或是销售部门来管理,而系统管理员只对于这些用户做授权或分派帐号与密码。
²
姓名:用户的真实姓名,见意系统管理员不要修改该内容,应由相关部门来维护该用户的姓名,如人力资源部、销售部、采购部的人员来修改该用户的姓名
²
部门:是个抽象的概念,如果当前用户是企业内部员工则它是企业内的部门或是分公司;如果当前用户是客户联系人则它是客户;如果当前用户是供应商联系人则它是供应商。同样的该信息应用相关部门的负责来维护,系统管理员不应随意修改
²
帐号:当前用户登录系统的帐号
²
密码:当前用户登录系统的密码,注意密码经过了加密处理在修改密码时一定要将该文本框中的内容全部清空后重新输入,否则用户将无法登录系统
²
帐号可用:用以设定该帐号是否可用,如果为否则该帐号无效,用户不能登录系统
²
加锁:对该帐号加锁,加锁后的帐号无法登录到系统。加锁与不可用表现形式相同即用户无法登录系统;区别在于加锁相当于将冻结该帐号在一段时间后来可以解锁,而不可用则是这个帐号常期失效后期对该帐号的用户不予维护例如员工离职时一定要将帐号设为不可用而非加锁
²
有效期至:可以为某个用户的帐号设置有效期,当超过有效期即使帐号是可用未加锁也无法登录到系统中,如果不填写用效期则视为该帐号不受时间限制始终可用
²
用户类型:分为
n
超级管理员:不受任何权限的限制,在应用系统中有无限的权力,可以看到与修改全部内容
n
一般用户:只能看到与修改他/她所拥有权限的内容
n
管理员:可以将自己已有的权限分派给他人
用户权限:
对应操作方案中的方案1,即将权限直截分派给指定的用户。这种方案适用于小型且用户数量很少的应用系统。该方案优点是操作直观易于理解,缺点是不易管理。
在为用户分派权限时,可以通过三种操作方式来完成。
在操作过程中,当您选择在不同用户间来回切换时,当前页面会自动刷新在“事项”一列只有是该用户所拥有的权限才会被选中,您可以在此为用户添加权限。页面最上部的是一排菜单项,在每个菜单项中都会有多个权限,在您在不同的菜单项中切换时,页面底部的权限列表会随之改变。对于权限范围与部门的处理请参见通用操作
3.
通过按钮,可以同时为多个用户分配多个权限。
在操作过程中,你可以通过查询条件查询到您要选择的用户,人员列表的最左则提供选取人员的复框,即表示您要对这些选中的用户进行批量授权。初始时权限列表的“事项”一列均未选中,您可以在此为选中的多个用户添加权限。页面中部的是一排菜单项,在每个菜单项中都会有多个权限,在您在不同的菜单项中切换时,页面底部的权限列表会随之改变。对于权限范围与部门的处理请参见通用操作
“单用户批量授权”与“多用户批量授权”的差异在于,在单用户批量授权中您可以看到所选中的用户目前所拥有的权限,而多用户批量授权则不能。
注意,无论是单用户批量授权还是多用户批量授权均不提供权限的删除功能,原因是同一个权限在同一个用户中有可能会有多个权限范围不同的副本,系统无法判断要删除这个用户这个权限的那一个副本。如果要为某个用户删除某些权限,可以通过用户权限列表删除之。
角色:
对应操作方案中的方案2,即将多个权限合并为一个角色,再将该角色分派给指定的用户。这种方案适用于中小型企业的应用系统。该方案优点操作简捷使用得当配置效率会很高,强烈推荐使用该方案实现安全管理。
²
角色名称:必须填写项,为角色定义一个名称中英文均可
²
描述:对该角色的描述
²
显示信息:没有意义,可以不填
在操作过程中,您必须为角色赋予一个名称,并填写该角色的描述信息,以方便日后记忆。页面底部的权限列表右侧的“事项”一列会显示该角色所拥有的权限,您可以在此为角色添加权限也可以为角色删除某些权限。页面中部的是一排菜单项,在每个菜单项中都会有多个权限,在您在不同的菜单项中切换时页面底部的权限列表会随之改变。对于权限范围与部门的处理请参见通用操作
步骤2. 将角色分派给用户
在操作过程中,你可以通过查询条件查询到您要选择的用户,人员列表的最左则提供选取人员的复框,即表示您要对这些选中的用户分派当前角色。页面的左下方是当前角色所拥有的权限,页面的右下方为所有拥有当前角色的用户列表,您可以通过用户列表“事项”
删除指定用户所拥有的当前角色。
目的
一般对于应用系统的授权过程:
权限
à角色(部门) à用户
过程描述:管理员将所要分组的权限分派给一个角色(一般会对应实际工作中一个岗位如出纳/仓库管理员…),并为当前角色指定一个部门(表示这个岗位是对哪个部门的管理)。
由此我们会发现,这个授权过程是链式的,即授权是一环套一环的,没有上一个环节的支持下一个环节就不能工作。本系统的实现目的正是为了打破授权的这种链式结构,实现在不同授权环节间的跳跃。如可以直接为用户分派权限,为用户分配角色等。
相关技术与依赖
Acegisecurity是基于SpringFramework的Web应用中安全框架,通过过滤器(javax.servlet.Filter)与拦截器(org.aopalliance.intercept.MethodInterceptor),于web的所请求的页面与所调用的方法进行拦截。以达到权限验证的目的。在本系统中作为身份验证与技术层上的授权实现的基本骨架。本文档假设对Acegi框架已有全面的了解。
Spring是AOP与IOC功能强大的逻辑层框架,本系统中逻辑层的调用均基于该框架
限制
ü
本系统所有验证与授权均是基于数据库的,不支持其它方式业务层面上的授权
ü
由于采用上述相关技术本系统仅限于在web上的应用,不支持C/S结构
ü
由于复杂度与适用性的原因,本系统不支持页面中各表单元素的权限可配置
ü
为了达到与部门有关的数据过滤的效果,所有业务相关的表中都要多加一个creator字段,作用是识标当前记录的创建人(由创建人可以找到部门),并且与业务表对应的POJO的属性名也应为creator
客户端用户授权处理
ü
权限管理(Authority):所有业务组件的权限均应由平台生成器自动生,并自动插入到数据库表,不提供终端用户对权限操作界面。如果开发阶段只能手动将权限插入数据库表中。
ü
角色管理(Role/ RoleAuthority):在功能上分为角色的创建与删除这两部分
1)
创建角色:创建角色的过程实际上也是为该角色分派权限的过程。按菜单层次结构列出所有权限(如果是管理员则只能列出所拥有的权限),并且只是权限类型是查询的,才会显示参考部门与范围,默认部门为空,范围为系统级。保存时,在Role表中增加一条记录,在RoleAuthority表根据终端用户所选择的权限及参考部门/范围等信息,增加n记录
2)
删除角色:首先是否有用户引用< UserRole >该角色,如果有引用则客户端抛出警告,否则删除Role/ RoleAuthority的相关记录
ü
分派权限管理(UserAuthority):左侧是组织结构树右侧为以菜单层次结构的权限列表(如果是管理员则只能列出所拥有的权限) ,并且只是权限类型是查询的,才会显示参考部门与范围,默认部门为空,范围为系统级。
ü
分派角色(UserRole):左侧是组织结构树右侧为角色列表,将与该角色s对应的<RoleAuthority>的信息赋到<UserAuthority>表中
页面表单的权限控制:由Acegi提供的taglib控制
对象定义源资源格式
平台为了方便对权限的对象定义源资源进行管理与扩展提供两种解决方案
方案一 现资源束形式管理
为了系统可以批量加载对象定义源实现资源束形式的管理,应提供对象定义源资源束格式的规范
1. 所有对象定义源的资源束文件均为properties文件,文件格式按properties规范处理,文件名为*-security.properties.生成器会自动将这些文件生成在java源代码的相应的服务包下
2. 文件内容针对不同的安全功能提供不同的开始/截止符作用功能分隔。它们分别为对于URL安全控制的为WEB_SECURITY/WEB_SECURITY_END,对于业务方法安全控制的开始/截止符分别为BUSINESS_SECURITY/BUSINESS_SECURITY_END。
方案二 数据库表形式管理
将所有权限对象定义源存放到数据库表HI_PrivilegeResource中,表结构如下:
字段名
|
数据类型
|
唯一
|
描述
|
id
|
int
|
Y
|
主键ID
|
version
|
Int
|
|
乐观锁定时的版本控制
|
authorityName
|
String(200)
|
Y
|
权限名
|
viewLayer
|
String(200)
|
|
表现层的动作,一般的对应一个action的url
|
veiwExtAuthNames
|
String(200)
|
|
该表现层动作还可容许访问的权限名,如果是多个权限用逗号(,)分隔
|
businessLayer
|
String(500)
|
|
业务层的方法,一般是类的全限定名包括方法名
|
bizExtAuthNames
|
String(200)
|
|
该业务层方法还可容许访问的权限名,如果是多个权限用逗号(,)分隔
|
与权限相关的配置文件
平台对于权限相关的配置文件存放在WEB_HOME/WEB-INFOr/config目录下,文件名为appContext-security.xml是一个Spring的配置文件,由于该文件较为复杂在此仅介绍常用的几处,具体的每段配置的目的请参见附录中Acgei与配置文件相关的类说明
<bean id="securityManager" parent="txProxyTemplate">
<property name="target">
<bean class="org.hi.framework.security.service.impl.SecurityManagerImpl">
<property name="DAO" ref="org.hi.framework.dao.DAO"/>
<property name="userClass" value="org.hi.base.organization.model.HiUser"/>
<property name="userAuthorityClass" value="org.hi.framework.security.model.UserAuthority"/>
</bean>
</property>
</bean>
安全管理器是后台的服务类,用于获取给定用户(即当前登录用户)的相关信息包括该用户的POJO、该用户所拥有的权限、角色等。UserContextHelper这个类在我们开发过程中经常用到它可以获得当前用户的所有信息,而这些信息的来源与组装过程就是在安全管理器这个服务类中完成的。该类中的userClass属性是指定用户POJO的类型,如果我们通过扩展实体的方式扩展了HiUser,应将该类型更改为扩展后实体的POJO类型
<bean id="filterInvocationInterceptor" class="org.hi.framework.security.acegi.ResourceBindleFilterSecurityInterceptor">
<property name="authenticationManager"><ref bean="authenticationManager"/></property>
<property name="accessDecisionManager"><ref local="accessDecisionManager"/></property>
<property name="mappingLocations"><value>classpath*:/**/*-security.properties</value></property>
<property name="alwaysReauthenticate" value="true"/>
<property name="runAsManager"><ref bean="runAsManager"/></property>
</bean>
表现层也就是Action的拦截器,通过HttpFilter在servlet执行任意一个action之前先被拦截认证当前用户是否有执行该url的权限,上面是资源束形式的管理方式,如要实现数据库表形式的管理方式,如下
<bean id="filterInvocationInterceptor" class="org.hi.framework.security.acegi.DataBaseFilterSecurityInterceptor">
<property name="authenticationManager"><ref bean="authenticationManager"/></property>
<property name="accessDecisionManager"><ref local="accessDecisionManager"/></property>
<property name="load" value="true"></property>
<property name="alwaysReauthenticate" value="true"/>
<property name="runAsManager"><ref bean="runAsManager"/></property>
</bean>
对于业务层的方法拦截器,资源束形式管理/数据库表形式管理,在配置上完全一致。
1.1
组织结构
从企业管理的角度来看,组织结构是指对于工作任务如何进行分工、分组和协调合作。从而使企业在组织上更加结构化、合理化以提高生产效率;从程序设计的角度来看,软件系统应适应企业组织在结构上的不断变化。
为了达到如上的要求,平台在设计上对于Hi_Org和Hi_User是两个抽象的表结构,对于Hi_Org来说它可以是公司、部门、客户、供应商等等;而对于Hi_User来说它可以是员工、客户联系人、供应商联系人等。因此在开发时可以通过平台继承实体的方式,扩展组织与人员实体从而实现不同类型的组织结构。
数据库表结构
Hi_Org组织表
字段名
|
数据类型
|
唯一
|
描述
|
ID
|
int
|
Y
|
主键ID
|
version
|
int
|
|
乐观锁定时的版本控制
|
orgName
|
String(50)
|
|
部门
|
orgNum
|
String(10)
|
|
部门编号
|
manager
|
int
|
|
部门的管理者,<User>
|
parentOrg
|
int
|
|
父部门,默认为0 <Org>
|
address
|
String(100)
|
|
地址
|
description
|
String(500)
|
|
备注/描述
|
Hi_User用户表
字段名
|
数据类型
|
唯一
|
描述
|
ID
|
int
|
Y
|
主键ID
|
version
|
Int
|
|
乐观锁定时的版本控制
|
userName
|
String(30)
|
Y
|
用户的登录账号
|
password
|
String(100)
|
|
用户密码,在数据库要求加密
|
country
|
int
|
|
对应枚举表[Language],是i18n的语种
|
timeZone
|
int
|
|
对应枚举表[TimeZone],是i18n的时区
|
accountEnabled
|
int
|
|
[YesNo],该帐号是否可用
|
accountLocked
|
int
|
|
[YesNo],是否锁住该帐号
|
expiredDate
|
Date
|
|
帐号的失效日期,null为永不失效
|
credentialsExpired
|
int
|
|
[YesNo],密码是否过期,预留不实现
|
fullName
|
String(30)
|
|
姓名
|
org
|
int
|
|
用户所在的部门
<Org>
|
gender
|
int
|
|
性别
|
address
|
String(200)
|
|
地址
|
phone
|
String(50)
|
|
电话
|
mobile
|
String(50)
|
|
手机
|
zip
|
String(30)
|
|
邮编
|
SSN
|
String(50)
|
|
证件号
|
mail
|
String(100)
|
|
电子邮箱
|
userMgrType
|
int
|
|
[ScurityUserMgrType] 超级管理员/管理员/一般用户
|
description
|
String(500)
|
|
备注/描述
|