在上一篇中我们研究了如何实现SpringSecurity中Jsp Tag的<security:authorize ifAllGranted="ROLE_SUPERVISOR">的功能。这一次我们一起研究一下如何实现在Tapestry5.1中添加一个Filter来对所有的操作进行权限的过滤控制。
在SpringSecurity中,我们一般是在application-context.xml中,添加一个SpringSecurity的Filter,然后在另外一个xml中详细配置如何根据Url的规则进行权限的控制。而Tapestry的哲学是尽量减少Xml中的配置(其IOC容器也基本上是借鉴Guice而不Spring的),所以我们也是在代码中实现权限规则的控制。
总体上来看,可以用两种方式来实现url规则,一种是Request级别的Filter,一种是页面组件级别的Filter,如果是Request级别的话,可以从Request对象中获取Url路径,这样就与SpringSecurity基本一样了。本文主要介绍页面组件级别的Filter,从中我们也可以体会到Tapestry5.1中的IOC容器的强大和便利。
这就是Filter的代码,这个Filter必须实现ComponentRequestFilter接口。值得注意的是其构造函数所需要用到的4个参数,这4个参数都是Tapestry5本身自有的服务,所以我们什么也不用做,Tapestry5自动会将服务的实例注入进来,这就是Tapestry-IOC的威力。
增加一个annotation, 如下:
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequiresLogin {
}
ComponentRequestFilter接口一共有4个方法需要实现,具体代码如下:
1
public
class
RequiresLoginFilter
implements
ComponentRequestFilter {
2
3
private
final
PageRenderLinkSource renderLinkSource;
4
5
private
final
ComponentSource componentSource;
6
7
private
final
Response response;
8
9
private
final
ApplicationStateManager appStateManager;
10
11
public
RequiresLoginFilter(PageRenderLinkSource renderLinkSource,
12
ComponentSource componentSource, Response response,
13
ApplicationStateManager appStateManager
14
) {
15
this
.renderLinkSource
=
renderLinkSource;
16
this
.componentSource
=
componentSource;
17
this
.response
=
response;
18
this
.appStateManager
=
appStateManager;
19
}
20
21
public
void
handleComponentEvent(
22
ComponentEventRequestParameters parameters,
23
ComponentRequestHandler handler)
throws
IOException {
24
25
if
(dispatchedToLoginPage(parameters.getActivePageName())) {
26
return
;
27
}
28
29
handler.handleComponentEvent(parameters);
30
31
}
32
33
public
void
handlePageRender(PageRenderRequestParameters parameters,
34
ComponentRequestHandler handler)
throws
IOException {
35
if
(dispatchedToLoginPage(parameters.getLogicalPageName())) {
36
return
;
37
}
38
handler.handlePageRender(parameters);
39
40
}
41
42
private
boolean
dispatchedToLoginPage(String pageName) {
43
Component page
=
componentSource.getPage(pageName);
44
45
if
(page.getClass().isAnnotationPresent(RequiresLogin.
class
)) {
46
if
(
!
appStateManager.exists(Authentication.
class
)) {
47
redirect();
48
return
true
;
49
}
50
Authentication auth
=
appStateManager.get(Authentication.
class
);
51
if
( auth
==
null
) {
52
redirect();
53
return
true
;
54
}
55
56
if
(
!
auth.isLoggedIn()) {
57
redirect();
58
return
true
;
59
}
60
61
RequiresLogin requireLogin
=
page.getClass().getAnnotation(
62
RequiresLogin.
class
);
63
String ifNotGranted
=
requireLogin.ifNotGranted();
64
String ifAllGranted
=
requireLogin.ifAllGranted();
65
String ifAnyGranted
=
requireLogin.ifAnyGranted();
66
boolean
permitted
=
auth.checkPermission(ifNotGranted, ifAllGranted, ifAnyGranted);
67
if
(
!
permitted ) {
68
return
true
;
69
}
70
}
71
72
return
false
;
73
}
74
75
private
void
redirect() {
76
Link link
=
renderLinkSource.createPageRenderLink(
"
Logout
"
);
77
78
try
{
79
response.sendRedirect(link);
80
}
catch
(Exception e) {
81
}
82
}
83
84
}
在ComponentRequestFilter中,我们无法使用@SessionState注解来直接注入Session中的变量,但是我们可以通过ApplicationStateManager来取得。
现在我们需要把刚定义的Filter注册到系统中,很简单,只要在AppModule中添加以下函数就行了:
1
public
static
void
contributeComponentRequestHandler(
2
OrderedConfiguration
<
ComponentRequestFilter
>
configuration) {
3
configuration.addInstance(
"
RequiresLogin
"
, RequiresLoginFilter.
class
);
4
}
5
从本例子中我们可以看到Tapesty Ioc容器使用的便利性,也认识到了Ioc容器在Tapestry体系中的重要性
转载自:http://www.blogjava.net/usherlight/archive/2010/02/04/312016.html, 并略加修改。