seam2.1权限验证(15.5)@Restrict注解 (一)

15.5. 错误消息安全API内嵌了针对各种安全相关操作的faces messages。下面这个表里面列出了在message.properties文件里面修改这些消息的message keys。如果想要禁用这些消息,只要在资源文件里面将这些错误消息的值置空就ok了。
Table 15.6. 安全消息

Message Key描述org.jboss.seam.loginSuccessful不用多说了,看字面就知道什么意思了org.jboss.seam.loginFailed org.jboss.seam.NotLoggedIn org.jboss.seam.AlreadyLoggedIn

15.6. 验证(Authorization)Seam Security API里面提供了很多权限验证的方法,无论是component、component method、或者页面上,你随时都可以进行权限验证相关的处理。这一节介绍了所有权限验证方面的内容。如果你需要使用任何高级特性(例如基于规则的权限验证),你一定要记住在components.xml文件里面指明(配置方法见前面的章节)。
15.6.1. 核心概念Seam安全模块就是用来让那些被授予了角色和(或)权限的人能够进行某些操作,并且阻止那些没有被授权的人进行这些相应操作的。Seam安全接口提供了验证用户权限的各种方法,这些方法都基于角色/权限概念。通过扩展框架功能,你还能同时使用多种方式来对程序的安全进行控制。
15.6.1.1. 什么是角色?一个角色就是一个组或者说是一种类型。这个组包含了用户可能会被赋予的一组权限(一组被许可在程序中进行的操作集合)。角色的结构很简单,仅仅由一个名称组成,例如“admin”、“user”、“customer”等。角色可以被赋予某个用户(有时也可能将角色赋予某个角色),并且可以用来对拥有相似操作权限的用户分组。


15.6.1.2. 什么是权限?权限就是进行某个操作(有时是一次性操作)的权利。在编写一个程序的时候,你完全可以只用权限来控制所有操作(这里指不适用角色的概念),但是有了角色,你就能进行一些更加“高级”的操作,例如将一组很多个权限同时赋予用户。权限比角色的结构稍微复杂点,主要包含三个属性:一个目标(target)、一个操作(action)、一个接受者(recipient)。权限的目标指接受者(或者说用户)被授权进行某一特殊操作的对象(可以是一个字符串的名称或者一个class)。例如,一个名叫Bob的用户拥有删除客户的权限,那么,删除用户这个权限的对象(target)为“客户”,权限的操作(action)为“删除”,权限的接受者(recipient)为“Bob”这个人。


在这个文档里面,我们通常将一个权限通过这种方式来表现:target:action(我们在这里忽略了接受者,但是在实际应用当中,接受者是必须的) 。
15.6.2. components验证让我们从最简单的验证方式开始——components验证。首先是@Restrict注解。
注意:@Restrict vs Typesafe security annotations
@Restrict能够使用EL表达式,所以它能够提供功能完善且灵活的验证方法。我们建议使用到的EL表达式应该是类型安全的,起码在编译的时候要保证它的安全。
15.6.2.1. @Restrict注解Seam组件可以通过使用添加@Restrict注解的方式来实现方法级别或者类级别的安全控制。如果一个方法和这个方法所在类同时使用了@Restrict注解,那么方法级别的安全限制优先级更高(意味着类级别的限制不起作用)。如果在方法上验证失败,那么与执行Identity.checkRestriction()方法一样抛出一个异常(参考相关的文档)。把@Restrict加在一个组件类上,相当于将这个约束加在了这个类的所有方法上。
一个空的@Restrict约束默认使用componentName:methodName作为权限的名称。例如以下这段代码:
Java代码

@Name("account")
public class AccountAction {
@Restrict public void delete() { ... }
}
@Name("account")public class AccountAction { @Restrict public void delete() { ... }}

在这个例子中,默认调用delete()方法需要account:delete权限。效果与
Java代码

@Restrict("#{s:hasPermission('account','delete')}")
@Restrict("#{s:hasPermission('account','delete')}")
相等。

再来看下面这段代码:
Java代码

@Restrict @Name("account")
public class AccountAction {
public void insert() {
...
}
@Restrict("#{s:hasRole('admin')}")
public void delete() {
...
}
}
@Restrict @Name("account")public class AccountAction { public void insert() { ... } @Restrict("#{s:hasRole('admin')}") public void delete() { ... }}
这种情况下,类上已经加了@Restrict,这就意味着所有没有加@Restrict的方法都需要进行默认的权限验证。在上面这个例子中,insert()方法需要权限account:insert,而delete()方法需要用户拥有admin角色。
当我们继续进行下一步之前,让我们在上面的代码中找到这个表达式:#{s:hasRole()}。s:hasRole和s:hasPermission都是EL表达式,分别对应Identity类里面的方法。这个方法能够用在所有EL表达式中,并且会用在所有安全验证相关的部分。
作为一个EL表达式,@Restrict注解的值可以关联到任何一个Seam上下文中存在的对象上。这在对某个具体的实例进行权限验证的时候非常有用:
面这个例子中,有一段代码比较有趣。就是在hasPermission()方法内部使用到了selectedAccount对象。此时,Seam会到上下文中寻找这个对象实例,并且将它传递给Identity对象的hasPermission()方法。这样就能判断出当前用户是否有权限来修改当前被注入的这个Account对象。
Java代码

@Name("account")
public class AccountAction {
@In Account selectedAccount;
@Restrict("#{s:hasPermission(selectedAccount,'modify')}")
public void modify() {
selectedAccount.modify();
}
}
@Name("account")public class AccountAction { @In Account selectedAccount; @Restrict("#{s:hasPermission(selectedAccount,'modify')}") public void modify() { selectedAccount.modify(); }}
15.6.2.2. 内部约束(Inline restrictions)有的时候你可能会需要在某个方法的代码内部检查权限,这样就无法使用@Restrict注解。这种情况下,你就需要用到Identity.checkRestriction()方法来执行一个与安全有关的表达式,例如:
Java代码

public void deleteCustomer() {
Identity.instance().checkRestriction("#{s:hasPermission(selectedCustomer,'delete')}");
}
public void deleteCustomer() { Identity.instance().checkRestriction("#{s:hasPermission(selectedCustomer,'delete')}");}
如果表达式未返回true则:
用户没有登录——抛出NotLoggedInException异常,
用户已经登录——抛出AuthorizationException异常。
同样的,你也可以在任何Java代码中使用hasRole()和hasPersmission()方法。
Java代码

if (!Identity.instance().hasRole("admin"))
throw new AuthorizationException("Must be admin to perform this action");

if (!Identity.instance().hasPermission("customer", "create"))
throw new AuthorizationException("You may not create new customers");
if (!Identity.instance().hasRole("admin")) throw new AuthorizationException("Must be admin to perform this action");if (!Identity.instance().hasPermission("customer", "create")) throw new AuthorizationException("You may not create new customers");
15.6.3. 程序界面中的安全控制(Security in the user interface)一个良好的用户界面设计需要符合一个特征,用户应该只看见他所能操作的部分,而用户没有权限看见或者没有权限进行操作的按钮链接等,不应该显示出来。Seam提供了两种根据权限控制界面显示内容的方法:
1)根据权限判断页面是否显示,
2)根据权限判断界面中的某个控件是否显示。这两种控制都使用EL表达式来判断。
我们来看几个权限控制的例子。
首先,一个登录表单需要只有当用户没有登录的时候才能看见。如果用户已经登录,那么就不需要显示登录表单。这个功能可以使用identity.isLoggedIn()属性来判断,在页面上,我们可以写成这样:
Xml代码

<h:form class="loginForm" rendered="#{not identity.loggedIn}">
<h:form class="loginForm" rendered="#{not identity.loggedIn}">
这种控制方式非常直观,看见代码的字面意思就应该能明白。下面,我们假设页面上有个显示所有报表的链接,这个链接只有当用户拥有manager角色的时候才能看见。我们在页面上可以这么写:
Xml代码

<h:outputLink action="#{reports.listManagerReports}" rendered="#{s:hasRole('manager')}">
Manager Reports
</h:outputLink>
<h:outputLink action="#{reports.listManagerReports}" rendered="#{s:hasRole('manager')}"> Manager Reports</h:outputLink>
这段代码也很直观。如果用户没有manager角色,那么这个链接就不会显示。通常rendered属性可以直接写在具体的标签内部,但是根据实际情况,也可以将它写在某个父标签上,例如<s:div>或<s:span>。
现在,我们来看一个复杂点的例子。假设页面上有一个h:dataTable,用于显示一个记录列表。表格的最后一列用来显示对当前记录的操作链接,这个链接需要根据用户拥有的权限来判断是否显示。s:hasPermission表达式允许我们将当前行的记录作为参数传入权限判断函数,并根据传入的对象以及当前登录的用户来判断是否显示。下面就是这个表格的代码:
Xml代码

<h:dataTable value="#{clients}" var="cl">
<h:column>
<f:facet name="header">Name</f:facet>
#{cl.name}
</h:column>
<h:column>
<f:facet name="header">City</f:facet>
#{cl.city}
</h:column>
<h:column>
<f:facet name="header">Action</f:facet>
<s:link value="Modify Client" action="#{clientAction.modify}"
rendered="#{s:hasPermission(cl,'modify')"/>
<s:link value="Delete Client" action="#{clientAction.delete}"
rendered="#{s:hasPermission(cl,'delete')"/>
</h:column>
</h:dataTable>
<h:dataTable value="#{clients}" var="cl"> <h:column> <f:facet name="header">Name</f:facet> #{cl.name} </h:column> <h:column> <f:facet name="header">City</f:facet> #{cl.city} </h:column> <h:column> <f:facet name="header">Action</f:facet> <s:link value="Modify Client" action="#{clientAction.modify}" rendered="#{s:hasPermission(cl,'modify')"/> <s:link value="Delete Client" action="#{clientAction.delete}" rendered="#{s:hasPermission(cl,'delete')"/> </h:column></h:dataTable>
15.6.4. 页面安全控制(Securing pages)页面安全控制需要程序里面有pages.xml文件,不过配置代码非常简单。只需要在page标签内部添加一个对象就能够实现安全控制。如果restrict对象没有任何属性或者子对象,那么默认情况下,来自non-faces (GET)的请求会需要权限/viewId.xhtml:render, JSF postback(来自表单提交方式)的请求会需要权限/viewId.xhtml:restore。此外,如果想要指定约束规则,那么只要写出标准的安全验证表达式即可。下面是几个例子:
Xml代码

<page view-id="/settings.xhtml">
<restrict/>
</page>
<page view-id="/settings.xhtml"> <restrict/></page>

Xml代码

<page view-id="/reports.xhtml">
<restrict>#{s:hasRole('admin')}</restrict>
</page>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值