key words: jsp,jstl,1.0,1.1,fn函数
原来一直用struts,最近项目里有人用jstl,我也就顺便拿来用,感觉还是不错。
过程中碰到一些小的问题总结如下:
一。版本问题
jstl存在1.0和1.1的差异问题,用EL建议需要在1.1的版本下,1.1的URI的标志为:
<%@ taglib uri=“http://java.sun.com/jsp/jstl/core“ prefix=“c“%>
<%@ taglib uri=“http://java.sun.com/jsp/jstl/functions“ prefix=“fn“%>
注意,1.0版本没有/jsp/.
如果用的1.0会出现如下异常
org.apache.jasper.JasperException: /public/left_tree.jsp(100,24) According to TLD or attribute directive in tag file, attribute items does not accept any expressions
org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:510)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:375)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:314)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:264)
javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:75)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:77)
com.wellsoon.zfzw.webapp.common.VabAccessFilter.doFilter(VabAccessFilter.java:43)
root cause
二。打开EL
<%@ page contentType=“text/html;charset=gb2312“ language=“java“ isELIgnored=“false“ %>
前提是容器支持2.0,即使支持默认也未必打开,最安全的方式就是显示打开 isELIgnored=“false“
三.fn的用法
对于Vo里的一个List作length的计算或判断很方便
<table width=”160″ border=”0″ cellspacing=”0″ cellpadding=”4″>
<c:forEach items=”${menuInfos}” var=”m”>
<c:if test=”${fn:length(m.subMenus)>0}”>
<tr>
<td>
<script language=”JavaScript”>
var tObj = new treeClass(“A1“)
tObj.start();
tObj.m_start(“<c:out value=“${m.menuModule}“/>“,0);
<c:forEach items=“${m.subMenus}“ var=“sub“>
tObj.add_Sub(“<c:out value=“${sub.menuName}“/>“,“<%=path%>
<c:out value=“${sub.url}“/>“,“mymain“);
</c:forEach>
tObj.m_end();
tObj.end();
tObj.print();
</script>
</td>
</tr>
</c:if>
</c:forEach>
</table>
四.tld的声明可以在web.xml作显式声明也可以用http作直接URL声明
推荐用本地的方式.
key words:jdk错误,Unsupported major.minor version
今天用一个工作流的产品,非要用jdk1.4的版本,没办法,只好切换回来,但是换回来后打开页面jsp出错,提示Unsupported major.minor version 49.0错误,到网上查了一下,49.0错误属于jdk1.5的错误,但是我的jdk1.5已经删除了啊?怎么回事呢?
最后想起来,可能是jboss中的1.5 版本产生临时文件class文件删除,删除后OK
key word: response.sendRedirect() 页面转向
在jsp里经常要碰到页面的跳转,但是有一个问题,就是跳转的时候有些信息无法携带,比如
response.sendRedirect(”myPage.jsp?method=save”)通过URL携带信息没问题,但是request.setAttribute(”message”,myObject);就无法携带. 以前碰到这个问题我都回避了,改用session存放信息,但是显然不足取。
察看了一下,在servlet里的途径好办,jsp里必须调用<jsp:forward>标签
<jsp:forward page=“myPage.jsp“/>
前言 :
权限往往是一个极其复杂的问题,但也可简单表述为这样的逻辑表达式:判断“ Who 对 What(Which) 进行 How 的操作”的逻辑表达式是否为真。针对不同的应用,需要根据项目的实际情况和具体架构,在维护性、灵活性、完整性等 N 多个方案之间比较权衡,选择符合的方案。
目标 :
直观,因为系统最终会由最终用户来维护,权限分配的直观和容易理解,显得比较重要,系统不辞劳苦的实现了组的继承,除了功能的必须,更主要的就是因为它足够直观。
简单,包括概念数量上的简单和意义上的简单还有功能上的简单。想用一个权限系统解决所有的权限问题是不现实的。设计中将常常变化的“定制”特点比较强的部分判断为业务逻辑,而将常常相同的“通用”特点比较强的部分判断为权限逻辑就是基于这样的思路。
扩展,采用可继承在扩展上的困难。的 Group 概念在支持权限以组方式定义的同时有效避免了重定义时
现状 :
对于在企业环境中的访问控制方法,一般有三种:
1. 自主型访问控制方法。目前在我国的大多数的信息系统中的访问控制模块中基本是借助于自主型访问控制方法中的访问控制列表 (ACLs) 。
2. 强制型访问控制方法。用于多层次安全级别的军事应用。
3. 基于角色的访问控制方法( RBAC )。是目前公认的解决大型企业的统一资源访问控制的有效方法。其显著的两大特征是: 1. 减小授权管理的复杂性,降低管理开销。 2. 灵活地支持企业的安全策略,并对企业的变化有很大的伸缩性。
名词 :
粗粒度:表示类别级,即仅考虑对象的类别 (the type of object) ,不考虑对象的某个特
定实例。比如,用户管理中,创建、删除,对所有的用户都一视同仁,并不区分操作的具体对象实例。
细粒度:表示实例级,即需要考虑具体对象的实例 (the instance of object) ,当然,细
粒度是在考虑粗粒度的对象类别之后才再考虑特定实例。比如,合同管理中,列表、删除,需要区分该合同实例是否为当前用户所创建。
原则 :
权限逻辑配合业务逻辑。即权限系统以为业务逻辑提供服务为目标。相当多细粒度的权限问题因其极其独特而不具通用意义,它们也能被理解为是“业务逻辑”的一部分。比如,要求:“合同资源只能被它的创建者删除,与创建者同组的用户可以修改,所有的用户能够浏览”。这既可以认为是一个细粒度的权限问题,也可以认为是一个业务逻辑问题。在这里它是业务逻辑问题,在整个权限系统的架构设计之中不予过多考虑。当然,权限系统的架构也必须要能支持这样的控制判断。或者说,系统提供足够多但不是完全的控制能力。即,设计原则归结为:“系统只提供粗粒度的权限,细粒度的权限被认为是业务逻辑的职责”。
需要再次强调的是,这里表述的权限系统仅是一个“不完全”的权限系统,即,它不提供所有关于权限的问题的解决方法。它提供一个基础,并解决那些具有“共性”的 ( 或者说粗粒度的 ) 部分。在这个基础之上,根据“业务逻辑”的独特权限需求,编码实现剩余部分 ( 或者说细粒度的 ) 部分,才算完整。回到权限的问题公式,通用的设计仅解决了 Who+What+How 的问题,其他的权限问题留给业务逻辑解决。
概念 :
Who :权限的拥用者或主体( Principal 、 User 、 Group 、 Role 、 Actor 等等)
What :权限针对的对象或资源( Resource 、 Class )。
How :具体的权限( Privilege, 正向授权与负向授权)。
Role :是角色,拥有一定数量的权限。
Operator :操作。表明对 What 的 How 操作。
说明 :
User : 与 Role 相关, 用户仅仅是纯粹的用户,权限是被分离出去了的。 User 是不能与 Privilege 直接相关的, User 要拥有对某种资源的权限,必须通过 Role 去关联。 解决 Who 的问题。
Resource :就是系统的资源,比如部门新闻,文档等各种可以被提供给用户访问的对象。资源可以反向包含自身,即树状结构,每一个资源节点可以与若干指定权限类别相关可定义是否将其权限应用于子节点。
Privilege :是 Resource Related 的权限。就是指,这个权限是绑定在特定的资源实例上的。比如说部门新闻的发布权限,叫做 “ 部门新闻发布权限 “ 。这就表明,该 Privilege 是一个发布权限,而且是针对部门新闻这种资源的一种发布权限。 Privilege 是由 Creator 在做开发时就确定的。权限,包括系统定义权限和用户自定义权限用户自定义权限之间可以指定排斥和包含关系 ( 如:读取,修改,管理三个权限,管理 权限 包含 前两种权限 ) 。 Privilege 如 “ 删除 ” 是一个抽象的名词,当它不与任何具体的 Object 或 Resource 绑定在一起时是没有任何意义的。拿新闻发布来说,发布是一种权限,但是只说发布它是毫无意义的。因为不知道发布可以操作的对象是什么。只有当发布与新闻结合在一起时,才会产生真正的 Privilege 。这就是 Privilege Instance 。权限系统根据需求的不同可以延伸生很多不同的版本。
Role :是粗粒度和细粒度 ( 业务逻辑 ) 的接口,一个基于粗粒度控制的权限框架软件,对外的接口应该是 Role ,具体业务实现可以直接继承或拓展丰富 Role 的内容, Role 不是如同 User 或 Group 的具体实体,它是接口概念,抽象的通称。
Group :用户组, 权限分配的单位与载体。权限不考虑分配给特定的用户。组可以包括组 ( 以实现权限的继承 ) 。 组可以包含用户,组内用户继承组的权限。 Group 要实现继承。即在创建时必须要指定该 Group 的 Parent 是什么 Group 。在粗粒度控制上,可以认为,只要某用户直接或者间接的属于某个 Group 那么它就具备这个 Group 的所有操作许可。细粒度控制上,在业务逻辑的判断中, User 仅应关注其直接属于的 Group ,用来判断是否“同组” 。 Group 是可继承的,对于一个分级的权限实现,某个 Group 通过“继承”就已经直接获得了其父 Group 所拥有的所有“权限集合”,对这个 Group 而言,需要与权限建立直接关联的,仅是它比起其父 Group 需要“扩展”的那部分权限。子组继承父组的所有权限,规则来得更简单,同时意味着管理更容易。为了更进一步实现权限的继承,最直接的就是在 Group 上引入“父子关系”。
User 与 Group 是多对多的关系。即一个 User 可以属于多个 Group 之中,一个 Group 可以包括多个 User 。子 Group 与父 Group 是多对一的关系。 Operator 某种意义上类似于 Resource + Privilege 概念,但这里的 Resource 仅包括 Resource Type 不表示 Resource Instance 。 Group 可以直接映射组织结构, Role 可以直接映射组织结构中的业务角色,比
较直观,而且也足够灵活。 Role 对系统的贡献实质上就是提供了一个比较粗颗粒的分配单位。
Group 与 Operator 是多对多的关系。各概念的关系图示如下:
Operator 的定义包括了 Resource Type 和 Method 概念。即, What 和 How 的概念。之所以将 What 和 How 绑定在一起作为一个 Operator 概念而不是分开建模再建立关联,这是因为很多的 How 对于某 What 才有意义。比如,发布操作对新闻对象才有意义,对用户对象则没有意义。
How 本身的意义也有所不同,具体来说,对于每一个 What 可以定义 N 种操作。比如,对于合同这类对象,可以定义创建操作、提交操作、检查冲突操作等。可以认为, How 概念对应于每一个商业方法。其中,与具体用户身份相关的操作既可以定义在操作的业务逻辑之中,也可以定义在操作级别。比如,创建者的浏览视图与普通用户的浏览视图要求内容不同。既可以在外部定义两个操作方法,也可以在一个操作方法的内部根据具体逻辑进行处理。具体应用哪一种方式应依据实际情况进行处理。
这样的架构,应能在易于理解和管理的情况下,满足绝大部分粗粒度权限控制的功能需要。但是除了粗粒度权限,系统中必然还会包括无数对具体 Instance 的细粒度权限。这些问题,被留给业务逻辑来解决,这样的考虑基于以下两点:
一方面,细粒度的权限判断必须要在资源上建模权限分配的支持信息才可能得以实现。比如,如果要求创建者和普通用户看到不同的信息内容,那么,资源本身应该有其创建者的信息。另一方面,细粒度的权限常常具有相当大的业务逻辑相关性。对不同的业务逻辑,常常意味着完全不同的权限判定原则和策略。相比之下,粗粒度的权限更具通用性,将其实现为一个架构,更有重用价值;而将细粒度的权限判断实现为一个架构级别的东西就显得繁琐,而且不是那么的有必要,用定制的代码来实现就更简洁,更灵活。
所以细粒度控制应该在底层解决, Resource 在实例化的时候,必需指定 Owner 和 GroupPrivilege 在对 Resource 进行操作时也必然会确定约束类型:究竟是 OwnerOK 还是 GroupOK 还是 AllOK 。 Group 应和 Role 严格分离 User 和 Group 是多对多的关系, Group 只用于对用户分类,不包含任何 Role 的意义; Role 只授予 User ,而不是 Group 。如果用户需要还没有的多种 Privilege 的组合,必须新增 Role 。 Privilege 必须能够访问 Resource ,同时带 User 参数,这样权限控制就完备了。
思想 :
权限系统的核心由以下三部分构成: 1. 创造权限, 2. 分配权限, 3. 使用权限,然后,系统各部分的主要参与者对照如下: 1. 创造权限 - Creator 创造, 2. 分配权限 - Administrator 分配, 3. 使用权限 - User :
1. Creator 创造 Privilege , Creator 在设计和实现系统时会划分,一个子系统或称为模块,应该有哪些权限。这里完成的是 Privilege 与 Resource 的对象声明,并没有真正将 Privilege 与具体 Resource 实例联系在一起,形成 Operator 。
2. Administrator 指定 Privilege 与 Resource Instance 的关联。在这一步, 权限真正与资源实例联系到了一起, 产生了 Operator ( Privilege Instance )。 Administrator 利用 Operator 这个基本元素,来创造他理想中的权限模型。如,创建角色,创建用户组,给用户组分配用户,将用户组与角色关联等等 … 这些操作都是由 Administrator 来完成的。
3. User 使用 Administrator 分配给的权限去使用各个子系统。 Administrator 是用户,在他的心目中有一个比较适合他管理和维护的权限模型。于是,程序员只要回答一个问题,就是什么权限可以访问什么资源,也就是前面说的 Operator 。程序员提供 Operator 就意味着给系统穿上了盔甲。 Administrator 就可以按照他的意愿来建立他所希望的权限框架 可以自行增加,删除,管理 Resource 和 Privilege 之间关系。可以自行设定用户 User 和角色 Role 的对应关系。 ( 如果将 Creator 看作是 Basic 的发明者, Administrator 就是 Basic 的使用者,他可以做一些脚本式的编程 ) Operator 是这个系统中最关键的部分,它是一个纽带,一个系在 Programmer , Administrator , User 之间的纽带。
用一个功能模块来举例子。
一.建立角色功能并做分配:
1 .如果现在要做一个员工管理的模块 ( 即 Resources) ,这个模块有三个功能,分别是:增加,修改,删除。给这三个功能各自分配一个 ID ,这个 ID 叫做功能代号:
Emp_addEmp , Emp_deleteEmp , Emp_updateEmp 。
2 .建立一个角色 (Role) ,把上面的功能代码加到这个角色拥有的权限中,并保存到数据库中。角色包括系统管理员,测试人员等。
3 .建立一个员工的账号,并把一种或几种角色赋给这个员工。比如说这个员工既可以是公司管理人员,也可以是测试人员等。这样他登录到系统中将会只看到他拥有权限的那些模块。
二.把身份信息加到 Session 中。
登录时,先到数据库中查找是否存在这个员工,如果存在,再根据员工的 sn 查找员工的权限信息,把员工所有的权限信息都入到一个 Hashmap 中,比如就把上面的 Emp_addEmp 等放到这个 Hashmap 中。然后把 Hashmap 保存在一个 UserInfoBean 中。最后把这个 UserInfoBean 放到 Session 中,这样在整个程序的运行过程中,系统随时都可以取得这个用户的身份信息。
三.根据用户的权限做出不同的显示。
可以对比当前员工的权限和给这个菜单分配的“功能 ID ”判断当前用户是否有打开这个菜单的权限。 例如:如果保存员工权限的 Hashmap 中没有这三个 ID 的任何一个,那这个 菜 单就不会显示,如果 员工 的 Hashmap 中有任何一个 ID ,那这个 菜 单都会显示。
对于一个新闻系统 (Resouce) ,假设它有这样的功能 (Privilege) :查看,发布,删除,修改;假设对于删除,有 “ 新闻系统管理者只能删除一月前发布的,而超级管理员可删除所有的这样的限制,这属于业务逻辑 (Business logic) ,而不属于用户权限范围。也就是说权限负责有没有删除的 Permission ,至于能删除哪些内容应该根据 UserRole or UserGroup 来决定 ( 当然给 UserRole or UserGroup 分配权限时就应该包含上面两条业务逻辑 ) 。
一个用户可以拥有多种角色,但同一时刻用户只能用一种角色进入系统。角色的划分方法可以根据实际情况划分,按部门或机构进行划分的,至于角色拥有多少权限,这就看系统管理员赋给他多少的权限了。用户—角色—权限的关键是角色。用户登录时是以用户和角色两种属性进行登录的(因为一个用户可以拥有多种角色,但同一时刻只能扮演一种角色),根据角色得到用户的权限,登录后进行初始化。这其中的技巧是同一时刻某一用户只能用一种角色进行登录。
针对不同的“角色”动态的建立不同的组, 每个项目建立一个单独的 Group ,对于新的项目,建立新的 Group 即可。在权限判断部分,应在商业方法上予以控制。比如:不同用户的“操作能力”是不同的 ( 粗粒度的控制应能满足要求 ) ,不同用户的“可视区域”是不同的 ( 体现在对被操作的对象的权限数据,是否允许当前用户访问,这需要对业务数据建模的时候考虑权限控制需要 ) 。
扩展性:
有了用户 / 权限管理的基本框架, Who(User/Group) 的概念是不会经常需要扩展的。变化的可能是系统中引入新的 What ( 新的 Resource 类型 ) 或者新的 How( 新的操作方式 ) 。那在三个基本概念中,仅在 Permission 上进行扩展是不够的。这样的设计中 Permission 实质上解决了 How 的问题,即表示了“怎样”的操作。那么这个“怎样”是在哪一个层次上的定义呢?将 Permission 定义在“商业方法”级别比较合适。比如,发布、购买、取消。每一个商业方法可以意味着用户进行的一个“动作”。定义在商业逻辑的层次上,一方面保证了数据访问代码的“纯洁性”,另一方面在功能上也是“足够”的。也就是说,对更低层次,能自由的访问数据,对更高层次,也能比较精细的控制权限。
确定了 Permission 定义的合适层次,更进一步,能够发现 Permission 实际上还隐含了 What 的概念。也就是说,对于 What 的 How 操作才会是一个完整的 Operator 。比如,“发布”操作,隐含了“信息”的“发布”概念,而对于“商品”而言发布操作是没有意义的。同样的,“购买”操作,隐含了“商品”的“购买”概念。这里的绑定还体现在大量通用的同名的操作上,比如,需要区分“商品的删除”与“信息的删除”这两个同名为“删除”的不同操作。
提供权限系统的扩展能力是在 Operator (Resource + Permission) 的概念上进行扩展。 Proxy 模式是一个非常合适的实现方式。实现大致如下:在业务逻辑层 (EJB Session Facade [Stateful SessionBean] 中 ) ,取得该商业方法的 Methodname ,再根据 Classname 和 Methodname 检索 Operator 数据,然后依据这个 Operator 信息和 Stateful 中保存的 User 信息判断当前用户是否具备该方法的操作权限。
应用在 EJB 模式下,可以定义一个很明确的 Business 层次,而一个 Business 可能意味着不同的视图,当多个视图都对应于一个业务逻辑的时候,比如, Swing Client 以及 Jsp Client 访问的是同一个 EJB 实现的 Business 。在 Business 层上应用权限较能提供集中的控制能力。实际上,如果权限系统提供了查询能力,那么会发现,在视图层次已经可以不去理解权限,它只需要根据查询结果控制界面就可以了。
灵活性 :
Group 和 Role ,只是一种辅助实现的手段,不是必需的。如果系统的 Role 很多,逐个授权违背了“简单,方便”的目的,那就引入 Group ,将权限相同的 Role 组成一个 Group 进行集中授权。 Role 也一样,是某一类 Operator 的集合,是为了简化针对多个 Operator 的操作。
Role 把具体的用户和组从权限中解放出来。一个用户可以承担不同的角色,从而实现授权的灵活性。当然, Group 也可以实现类似的功能。但实际业务中, Group 划分多以行政组织结构或业务功能划分;如果为了权限管理强行将一个用户加入不同的组,会导致管理的复杂性。
Domain 的应用。为了授权更灵活,可以将 Where 或者 Scope 抽象出来,称之为 Domain ,真正的授权是在 Domain 的范围内进行,具体的 Resource 将分属于不同的 Domain 。比如:一个新闻机构有国内与国外两大分支,两大分支内又都有不同的资源(体育类、生活类、时事政治类)。假如所有国内新闻的权限规则都是一样的,所有国外新闻的权限规则也相同。则可以建立两个域,分别授权,然后只要将各类新闻与不同的域关联,受域上的权限控制,从而使之简化。
权限系统还应该考虑将功能性的授权与资源性的授权分开。很多系统都只有对系统中的数据(资源)的维护有权限控制,但没有对系统功能的权限控制。
权限系统最好是可以分层管理而不是集中管理。大多客户希望不同的部门能且仅能管理其部门内部的事务,而不是什么都需要一个集中的 Administrator 或 Administrators 组来管理。虽然你可以将不同部门的人都加入 Administrators 组,但他们的权限过大,可以管理整个系统资源而不是该部门资源。
正向授权与负向授权:正向授权在开始时假定主体没有任何权限,然后根据需要授予权限,适合于权限要求严格的系统。负向授权在开始时假定主体有所有权限,然后将某些特殊权限收回。
权限计算策略:系统中 User , Group , Role 都可以授权,权限可以有正负向之分,在计算用户的净权限时定义一套策略。
系统中应该有一个集中管理权限的 AccessService ,负责权限的维护(业务管理员、安全管理模块)与使用(最终用户、各功能模块),该 AccessService 在实现时要同时考虑一般权限与特殊权限。虽然在具体实现上可以有很多,比如用 Proxy 模式,但应该使这些 Proxy 依赖于 AccessService 。各模块功能中调用 AccessService 来检查是否有相应的权限。所以说,权限管理不是安全管理模块自己一个人的事情,而是与系统各功能模块都有关系。每个功能模块的开发人员都应该熟悉安全管理模块,当然,也要从业务上熟悉本模块的安全规则。
技术实现 :
1 .表单式认证,这是常用的,但用户到达一个不被授权访问的资源时, Web 容器就发
出一个 html 页面,要求输入用户名和密码。
2 .一个基于 Servlet Sign in/Sign out 来集中处理所有的 Request ,缺点是必须由应用程序自己来处理。
3 .用 Filter 防止用户访问一些未被授权的资源, Filter 会截取所有 Request/Response ,
然后放置一个验证通过的标识在用户的 Session 中,然后 Filter 每次依靠这个标识来决定是否放行 Response 。
这个模式分为:
Gatekeeper :采取 Filter 或统一 Servlet 的方式。
Authenticator : 在 Web 中使用 JAAS 自己来实现。
用户资格存储 LDAP 或数据库:
1. Gatekeeper 拦截检查每个到达受保护的资源。首先检查这个用户是否有已经创建
好的 Login Session ,如果没有, Gatekeeper 检查是否有一个全局的和 Authenticator 相关的 session ?
2. 如果没有全局的 session ,这个用户被导向到 Authenticator 的 Sign-on 页面,
要求提供用户名和密码。
3. Authenticator 接受用户名和密码,通过用户的资格系统验证用户。
4. 如果验证成功, Authenticator 将创建一个全局 Login session ,并且导向 Gatekeeper
来为这个用户在他的 web 应用中创建一个 Login Session 。
5. Authenticator 和 Gatekeepers 联合分享 Cookie ,或者使用 Tokens 在 Query 字符里。
访问控制背景
访问控制技术是由美国国防部(Department of Defense, DoD)资助的研究和开发成果演变而来的。这一研究导致两种基本类型访问控制的产生:自主访问控制(Discretionary Access Control, DAC)和强制访问控制(Mandatory Access Control, MAC)。最初的研究和应用主要是为了防止机密信息被未经授权者访问,近期的应用主要是把这些策略应用到为商业领域。
自主访问控制,允许把访问控制权的授予和取消留给个体用户来判断。为没有访问控制权的个体用户授予和废除许可。自主访问控制机制允许用户被授权和
取消访问其控制之下的任何客体(object),换句话说,用户就是他们控制下的客体的拥有者。然而,对于多数组织来说,最终用户对所访问的信息没有拥有权。对于这些组织,公司或代理机构是事实上的系统客体和处理他们的程序的拥有者。访问优先权受组织控制,而且也常常基于雇员功能而不是数据所有权。
强制访问控制,在美国国防部 Trusted Computer Security Evaluation Criteria (TCSEC) 中定义如下:“一种限制访问客体的手段,它以包含在这些客体中的信息敏感性和访问这些敏感性信息的主体的正式授权信息(如清除)为基础”。
以上访问控制策略对于处理一些无需保密但又敏感的信息的政府和行业组织的需求并不是特别的适合。在这样的环境下,安全目标支持产生于现有法律、道德规范、规章、或一般惯例的高端组织策略。这些环境通常需要控制个体行为的能力,而不仅仅是如何根据信息的敏感性为其设置标签从而访问这一信息的个人能力。
什么是基于角色访问控制(Role-Based Access Control, RBAC)?NIST 有如下定义。
访问是一种利用计算机资源去做某件事情的的能力,访问控制是一种手段,通过它这种能力在某些情况下被允许或者受限制(通常是通过物理上和基于系统的控制)。基于计算机的访问控制不仅可规定是“谁”或某个操作有权使用特定系统资源,而且也能规定被允许的访问类型。这些控制方式可在计算机系统或者外部设备中实现。
就基于角色访问控制而言,访问决策是基于角色的,个体用户是某个组织的一部分。用户具有指派的角色(比如医生、护士、出纳、经理)。定义角色的过程应该基于对组织运转的彻底分析,应该包括来自一个组织中更广范围用户的输入。
访问权按角色名分组,资源的使用受限于授权给假定关联角色的个体。例如,在一个医院系统中,医生角色可能包括进行诊断、开据处方、指示实验室化验等;而研究员的角色则被限制在收集用于研究的匿名临床信息工作上。
控制访问角色的运用可能是一种开发和加强企业特殊安全策略,进行安全管理过程流程化的有效手段。
用户(User)和角色(Role)
用户指访问系统中的资源的主体,一般为人,也可为 Agent 等智能程序。角色指应用领域内一种权力和责任的语义综合体,可以是一个抽象概念,也可以是对应于实际系统中的特定语义体,比如组织内部的职务等。针对角色属性的不同,某些模型中将角色进一步细分为普通角色和管理员角色(可理解为全局角色)。
许可(Permissions)和权限(Permission)
许可描述了角色对计算机资源的访问和操作所具有的权限,其反映的是授权的结果。比如授予某个角色对计算机资源有读的权限,则代表了一个许可的存在,这个许可表示:角色获取了对计算机资源的读许可。针对操作来说,其描述的是许可和操作之间的一种关联关系,而这层关系则表示了某一角色对某一操作所具有的权限及权限状态。
角色和指派(Assignment)
指派包含两个方面,用户指派和许可指派。用户指派表示的是,将用户指派给特定的角色。许可指派表示的是为角色指派计算机资源的访问和操作许可。
会话(session)
会话表示的是用户和角色之间的关系。用户每次必须通过建立会话来激活角色,得到相应的访问权限。
角色和角色等级(Role Hierarchies)
角色本身仅仅只是一个名词,其本身并不能代表权限的大小。比如,我们可以定一个“Director”的角色,也可以定一个“Project Leader”的角色。对于现实中我们来说,看到这样两个角色,就清楚 DIR 的权限要比一个 PL 的权限级别高。但是对计算机来说,这两个角色仅仅是两个“词语”,是等同的。可以采用分等级角色,在角色上实现层次化来解决这些问题。也可以采用复合角色(其表示的就是一个角色组的概念),对角色实现一定的分组和复合,以便于权限指派。在一些 OA 产品中经常出现分等级角色。
限制(Constraints)
模型中的职责分离关系(Separation of Duty),用于控制冲突(Conflict)。静态职责分离(Static SD)指定角色的互斥关系,用于用户指派阶段。避免同一用户拥有互斥的角色。实现简单,角色互斥语义关系清楚,便于管理不够灵活,不能处理某些实际情况。动态职责分离(Dynamic SD)指定角色的互斥关系,用于角色激活阶段。允许同一用户拥有某些互斥的角色,但是不允许该用户同时激活互斥的角色。更灵活,直接与会话挂钩,适应实际管理需要,实现复杂,不易管理。
参考文献
《AN INTRODUCTION TO ROLE-BASED ACCESS CONTROL》 NIST《工作流授权控制模型》 胡长城
《基于角色的权限管理综述》 俞诗鹏
最后,感谢宏云博士对本文翻译提供的指导。
请注意!引用、转贴本文应注明原作者:Rosen Jiang 以及出处:http://www.blogjava.net/rosen
key words: 门面与代理,设计模式
这两组内容没有联系,只是今天在路上的时候突然一下子想到了,就放在一起说说吧
Facade与proxy大多数人应该很熟悉,也接触了不少,但是放在一起比较问他们有什么具体区别的时候好像一下子也说得很含糊。
Facade 意为门面,proxy意为代理,中文的解释也很通俗,但是有时候感觉Facade也有代理的味道,有人认为二者都属于proxy这个大概念,但是问题是他们总得有不同的用途吧,否则发明这两个词岂不是浪费?
google了一些说法,下面这个说法比较到位:
Facade: 用于隐藏调用的复杂性
proxy: 放在服务期端保护被访问的对象
我个人的理解是:
对于客户端掉用来说,Facade是一定可见的,proxy是不可见的 .
比如,一个报刊亭卖报纸,可能有人民日报,新华日报等多家送报纸给他们的人,但是我们直接到他的店面就可以取到我们想要的报纸,而不是买人民日报的时候到人民日报社去取,以此类推.
而proxy对我们是隐藏的,比如Jive论坛里的权限验证,我们发帖子的时候客户端是透明访问的,压根实际在服务端后台作了isAdmin和isGuest的判断
Facade仅仅是提供了你一个方便的 “门面”,你可以把它理解为超市,你只要到他那里就可以取到你想要的东西,但是他所调用的后台仍然可以根据策略开放给客户端,比如我们完全可以不去报刊亭买报纸,我们自己去人民日报社去取,但是这种做法显然在如今的现代化潮流下是没什么提倡的,现在更提倡分工.
对于proxy我们仍有一个误解,比如问你”中介公司是proxy吗?” 请思考一下
很多人认为中介公司是代理,因为我们生活中有时候就直接称中介公司为代理商或代理公司等,但是此代理非彼代理也! 为什么? 参照我们上面所说的proxy的特征,proxy是隐藏的,难道我们联系代理公司的地址时他会说 : “打一枪换一个地方” 么? 显然不是,恰恰相反,中介公司事实上反而是我们java里的Facade模式,因为它是可见的.
好,关于facade 与proxy就说到这里,应该很清楚了.
Facade用的非常的广了,以前刚接触的时候有个误解,总觉得Facade是简单的,而它后面的支撑服务是复杂的,对于客户来说却是简单的,现在来看,不完全对,或者说只是说对了一半,因为有时候恰恰是Facade是复杂的.
我们举一个例子,比如发送短信,我们一般就定义一个MessageService的服务类,里面只提供一个方法就行了,sendToUser(String phone,String content)
但是到了客户端的时候有了自己的 “方言”,比如它不是关心一个抽象的用户,它只知道向教师发送短信,或者向学生发送短信,或者向家长发送短信。
示例如下:
![]()
由图中可以看到,Facade的内容非常丰富,而支撑它的服务类却很简单,在开发过程中我们一般先实现通用的ServiceA,然后根据进一步的需求做一个面向具体复杂的Facade.
在Spring提供的sample里发现一个小技巧,就是Facade和ServiceA都是接口,然后提供一个实现二者的支撑类:
public class PetStoreAnnotationImpl implements PetStoreFacade, OrderService {
private AccountDao accountDao;
private CategoryDao categoryDao;
private ProductDao productDao;
private ItemDao itemDao;
private OrderDao orderDao;
//————————————————————————-
// Setter methods for dependency injection
//————————————————————————-
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
public void setCategoryDao(CategoryDao categoryDao) {
this.categoryDao = categoryDao;
}
public void setProductDao(ProductDao productDao) {
this.productDao = productDao;
}
public void setItemDao(ItemDao itemDao) {
this.itemDao = itemDao;
}
public void setOrderDao(OrderDao orderDao) {
this.orderDao = orderDao;
}
//————————————————————————-
// Operation methods, implementing the PetStoreFacade interface
//————————————————————————-
public Account getAccount(String username) {
return this.accountDao.getAccount(username);
}
public Account getAccount(String username, String password) {
return this.accountDao.getAccount(username, password);
}
public void insertAccount(Account account) {
this.accountDao.insertAccount(account);
}
public void updateAccount(Account account) {
this.accountDao.updateAccount(account);
}
public List getUsernameList() {
return this.accountDao.getUsernameList();
}
public List getCategoryList() {
return this.categoryDao.getCategoryList();
}
public Category getCategory(String categoryId) {
return this.categoryDao.getCategory(categoryId);
}
public List getProductListByCategory(String categoryId) {
return this.productDao.getProductListByCategory(categoryId);
}
public List searchProductList(String keywords) {
return this.productDao.searchProductList(keywords);
}
public Product getProduct(String productId) {
return this.productDao.getProduct(productId);
}
public List getItemListByProduct(String productId) {
return this.itemDao.getItemListByProduct(productId);
}
public Item getItem(String itemId) {
return this.itemDao.getItem(itemId);
}
public boolean isItemInStock(String itemId) {
return this.itemDao.isItemInStock(itemId);
}
public void insertOrder(Order order) {
this.orderDao.insertOrder(order);
this.itemDao.updateQuantity(order);
}
public Order getOrder(int orderId) {
return this.orderDao.getOrder(orderId);
}
public List getOrdersByUsername(String username) {
return this.orderDao.getOrdersByUsername(username);
}
}
看起来似乎不错,不过仔细想想个人认为还是不是太好,总的感觉就是层次不清晰,因为很多时候Facade和Service之间是被服务与服务的关系,所以理当分开。 同时,这个类有点倾向于”万能类”了,能分还是分开好.这和我们以前提到的dao又背离过来了(以前我们提倡一个业务一个dao,现在觉得只用一个通用的dao更合适),这个并不矛盾,具体问题具体看待.
欢迎各位拍砖.
板桥里人 http://www.jdon.com 2002/05/05(转载请保留)
Visitor访问者模式定义
作用于某个对象群中各个对象的操作. 它可以使你在不改变这些对象本身的情况下,定义作用于这些对象的新操作.
在Java中,Visitor模式实际上是分离了collection结构中的元素和对这些元素进行操作的行为.
为何使用Visitor?
Java的Collection(包括Vector和Hashtable)是我们最经常使用的技术,可是Collection好象是个黑色大染缸,本来有各种鲜明类型特征的对象一旦放入后,再取出时,这些类型就消失了.那么我们势必要用If来判断,如:
Iterator iterator = collection.iterator()
while (iterator.hasNext()) {
Object o = iterator.next();
if (o instanceof Collection)
messyPrintCollection((Collection)o);
else if (o instanceof String)
System.out.println(”‘”+o.toString()+”‘”);
else if (o instanceof Float)
System.out.println(o.toString()+”f”);
else
System.out.println(o.toString());
}
在上例中,我们使用了 instanceof来判断 o的类型.
很显然,这样做的缺点代码If else if 很繁琐.我们就可以使用Visitor模式解决它.
如何使用Visitor?
针对上例,定义接口叫Visitable,用来定义一个Accept操作,也就是说让Collection每个元素具备可访问性.
被访问者是我们Collection的每个元素Element,我们要为这些Element定义一个可以接受访问的接口(访问和被访问是互动的,只有访问者,被访问者如果表示不欢迎,访问者就不能访问),取名为Visitable,也可取名为Element。
| public interface Visitable { public void accept(Visitor visitor); } |
被访问的具体元素继承这个新的接口Visitable:
| public class StringElement implements Visitable { private String value; public StringElement(String string) { value = string; } public String getValue(){ |
上面是被访问者是字符串类型,下面再建立一个Float类型的:
| public class FloatElement implements Visitable { private Float value; public FloatElement(Float value) { this.value = value; } public Float getValue(){ |
我们设计一个接口visitor访问者,在这个接口中,有一些访问操作,这些访问操作是专门访问对象集合Collection中有可能的所有类,目前我们假定有三个行为:访问对象集合中的字符串类型;访问对象集合中的Float类型;访问对象集合中的对象集合类型。注意最后一个类型是集合嵌套,通过这个嵌套实现可以看出使用访问模式的一个优点。
接口visitor访问者如下:
| public interface Visitor { public void visitString(StringElement stringE); } |
访问者的实现:
| public class ConcreteVisitor implements Visitor { //在本方法中,我们实现了对Coll |