让我们以@Restrict
注释来研究最简单的授权和组件安全为开端。
@Restrict
意味着一个默认的权限检查:componentName:methodName
。如下所示:@Name("account")
public class AccountAction {
@Restrict public void delete() {
}
}
在这个例子中,调用public class AccountAction {
@Restrict public void delete() {
}
}
delete()
方法时需要的隐含权限是account:delete
。与@Restrict("#{s:hasPermission('account','delete')}")
这样写是等价的。现在,让我们看看另外一个例子:@Restrict @Name("account")
public class AccountAction {
public void insert() {
}
@Restrict("#{s:hasRole('admin')}")
public void delete() {
}
}
这次,组件类本身使用了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函数,贯穿整个安全API,这些函数能在任何EL表达式是使用。
@Restrict
注释的值可以引用存在于Seam上下文中的任何对象。这在为一个指定的对象实例执行权限检查是非常有用的。看这个例子: @Name("account")
public class AccountAction {
@In Account selectedAccount;
@Restrict("#{s:hasPermission(selectedAccount,'modify')}")
public void modify() {
selectedAccount.modify();
}
}
在这个例子中需要说明的有趣的一点是public class AccountAction {
@In Account selectedAccount;
@Restrict("#{s:hasPermission(selectedAccount,'modify')}")
public void modify() {
selectedAccount.modify();
}
}
hasPermission()
函数调用了selectedAccount
方法的引用。该变量值将在Seam上下文中查找,并传递给Identity
的hasPermission()
方法,在本例中它将确定用户是否有必须的修改指定Account
对象的权限。 有时它也可以在声明在代码中来执行安全检查,而不使用@Restrict
注释。在这种情况下,简单的使用Identity.checkRestriction()
来评估安全表达式,就像这样:public void deleteCustomer() {
Identity.instance().checkRestriction("#{s:hasPermission(selectedCustomer,'delete')}");
}
如果这个指定表达式评估后不为Identity.instance().checkRestriction("#{s:hasPermission(selectedCustomer,'delete')}");
}
true
,并且 也可以在Java代码中直接调用hasRole()
和hasPermission()
方法: 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");
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");
作为一个优良设计的用户界面的指标之一就是用户不会看见它没有权限使用的选项。基于以上的用户的特权,使用非常一致的组件安全性EL表达式,Seam安全允许有条件的渲染 1)页面的区段和 2)独立的控件。
让我们看看一些界面安全的例子。首先,假设我们有一个登录表单,它只能在用户没有登录的时候被渲染。使用identity.isLoggedIn()
特性,我们可以这样写: <h:form class="loginForm" rendered="#{not identity.loggedIn}">
如果用户没有登录,那么登录表单将被渲染-到目前为止,非常简单。现在,假设页面上有一个菜单,它包含一些只能被是“manager
”角色的用户访问的动作。可以写成这样: <h:outputLink action="#{reports.listManagerReports}" rendered="#{s:hasRole('manager')}">
Manager Reports
</h:outputLink>
这也相当直截了当。如果用户不是Manager Reports
</h:outputLink>
manager
角色的成员,那么这个outputlink将不会被渲染。rendered
属性通常是控件本身使用,或者是一个被包围的<s:div>
或<s:span>
控件。 <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: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>