Tapestry中并沒有類似于Spring Security這樣的專門的權限框架。對此Tapestry的作者Lewis認為主要是用戶對于權限的要求實在太多變化了。他認為很難抽象出一個通用的權限框架來滿足所有的用戶,所以他干脆就不費事去做這件事了。但其實我們很容易就能利用Tapestry已有的工具來完成類似于SpringSecurity的功能。
本文主要介紹如何實現類似于SpringSecurity的jsp tag的功能。在Tapestry中,利用Components實現這一點非常容易。
其基本原理是Tapestry5中一個頁面或者組件的渲染生成過程是基于一個狀態機和隊列完成的。這樣,渲染生成過程就被細分成了很多個小模塊,我們可以非常容易地覆寫這些小模塊。具體內容詳見官方文檔:http://tapestry.apache.org/tapestry5.1/guide/rendering.html。如果權限校驗不通過,我們就可以控制不顯示組件的內容。
我們這里就是主要依賴這個過程來實現在頁面這一層面對權限進行校驗和控制。
代碼主要包含兩大部分,一個組件和一個用于權限控制的服務。
參考了Tapestry-Spring-Security的實現,我也將組件命名為IfRole(當然,我們也可以和Tapestry-Spring-Security一樣,也再生成一個IfLoggedIn組件)。權限控制的服務我命名為:AuthenticationService。
主要的實現思路:
將AuthenticationService申明為SessionState變量。這樣這個變量就可以在所有的頁面和組件之間很方便地共享了。一般情況下,是在登錄頁面對AuthenticationService進行賦值,而在退出頁面清空AuthenticationService這個變量。
代碼(這部分代碼完全根據應用的需求進自行更改):
AuthenticationService的代碼:

public class AuthenticationService
{
private List<String> privilegeList;
// privilegeList 的getter and setter

public boolean checkPermission(String ifNotGranted, String ifAllGranted,

String ifAnyGranted)
{
if (((null == ifAllGranted) || "".equals(ifAllGranted))
&& ((null == ifAnyGranted) || "".equals(ifAnyGranted))

&& ((null == ifNotGranted) || "".equals(ifNotGranted)))
{
return false;
}


if ((null != ifNotGranted) && !"".equals(ifNotGranted))
{
StringTokenizer st = new StringTokenizer(ifNotGranted, ",");

while (st.hasMoreTokens())
{
String value = st.nextToken();

if (privilegeList.contains(value))
{
return false;
}
}
}


if ((null != ifAllGranted) && !"".equals(ifAllGranted))
{
StringTokenizer st = new StringTokenizer(ifAllGranted, ",");

while (st.hasMoreTokens())
{
String value = st.nextToken();

if (!privilegeList.contains(value))
{
return false;
}
}
}


if ((null != ifAnyGranted) && !"".equals(ifAnyGranted))
{
StringTokenizer st = new StringTokenizer(ifAnyGranted, ",");

while (st.hasMoreTokens())
{
String value = st.nextToken();

if (privilegeList.contains(value))
{
return true;
}
}
return false;
}

return true;
}
}
IfRole的代碼(這個類需要放在Components目錄下):

public class IfRole
{

/** *//**
* A comma-separated list of roles is supplied to one or more of the
* following parameters. If none are supplied, the default behavior is to
* forbid access. Behavior should be self-explanatory.
*/
@Parameter(required = false, defaultPrefix = "literal")
private String ifAllGranted;

@Parameter(required = false, defaultPrefix = "literal")
private String ifAnyGranted;

@Parameter(required = false, defaultPrefix = "literal")
private String ifNotGranted;


/** *//**
* An alternate {@link Block} to render if the test parameter is false. The default, null, means
* render nothing in that situation.
*/
@Parameter(name = "else")
private Block elseBlock;

private boolean test;
@SessionState
private AuthenticationService auth;


private boolean checkPermission()
{
return auth.checkPermission(ifNotGranted, ifAllGranted, ifAnyGranted);
}

void setupRender()
{
test = checkPermission();
}


/** *//**
* Returns null if the test method returns true, which allows normal
* rendering (of the body). If the test parameter is false, returns the else
* parameter (this may also be null).
*/

Object beginRender()
{
return test ? null : elseBlock;
}


/** *//**
* If the test method returns true, then the body is rendered, otherwise not. The component does
* not have a template or do any other rendering besides its body.
*/

boolean beforeRenderBody()
{
return test;
}
}
示例:
1. 在登錄頁面:
@SessionState
private Authentication auth;
......
// if user name and password is valid:
auth.setPrivliegeList(.....);
2. 在需要權限控制的頁面模板中:
<t:ifRole ifAllGranted="admin">
administrator can see this block
</t:ifRole>