云自无心水自闲

天平山上白云泉,云自无心水自闲。何必奔冲山下去,更添波浪向人间!
posts - 288, comments - 524, trackbacks - 0, articles - 6
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

在上一篇中我们研究了如何实现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的威力。
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体系中的重要性


评论

# re: Tapestry最新版5.1.0.5教程(九):权限控制框架的实现-进阶篇  回复  更多评论   

2010-12-25 23:22 by linuxboy
这个方法我正在使用,但是有一个不是很完美的地方:用户登录后不能返回上一个页面,尤其是包含context参数的页面或者是request parameters的页面。
比如:http://none.com/edituser/12
http://none.com/edituser?userId=12

只有注册用户登录后才能发表评论。


网站导航: