问题引入:
我们通常的系统中仅仅做了Web层访问权限控制,因为大多系统只有Web方式的UI做为人机交互的接口,不提供其它的客户端,所以业务逻辑访问控制一般可以不用控制,数据访问方面由于一般系统的要求目前尚未达到这一权限控制的必要,也没有完整的进行控制。Web层的URL级控制通常采用J2EE规范中的Filter来解决,但由于JSF中的跳转并不会重写URL,默认采用Forward的方式,一般不会采用Redirect的方式,而且采用Redirect的时候,开发时会很不方便,很多Request参数无法传递,所以我们实际上在Filter中获得的URI往往都不是真实的地址。
实际案例:
我们现在有一个画面,假如从菜单中进入画面的URI为“list.jsf”,画面上有“新增”、“查询”两个Button,当点击“查询”这个Button时,查询结果并显示在“list.jsf”这个页面上,当点击“新增”这个Button时,跳转到“add.jsf”这个页面,新增画面中还有一个“返回”Button。当我们点击“新增”时,在Filter中得到的URI为“list.jsf”,实际上我们要跳转到“add.jsf”这个页面,当我们点击“返回”Button时,Filter中得到URI的是“add.jsf”,这与我们实际要跳转到的页面“list.jsf”又不符。如果我们仅仅在Filter中根据URI来判断权限,那么当一个用户不具有新增权限时,就会出现可以操作新增功能的事情,这样便未达到权限控制的目的。
问题解决:
JSF提供了自定义Application的可能,通过研究JSF的实现可以发现JSF控制页面的跳转都是在NavigationHandler中完成的。那么我们来试着实现一个自己的NavigationHandler,解决这一问题。先给出详细的实现:
1public class NavigationHandleWithAuthImpl extends NavigationHandler {
2
3 /** *//**
4 * Field DEBUGLOG.
5 */
6 private static final Logger DEBUGLOG = Logger.getLogger(Constant.LOG_DEBUG);
7
8 /** *//**
9 * Field ERRORLOG.
10 */
11 private static final Logger ERRORLOG = Logger.getLogger(Constant.LOG_ERROR);
12
13 /** *//**
14 * Field IGNORED_URI.
15 */
16 private static final String IGNORED_URI = "/login.faces; /send.faces; "
17 + "/mainlayout.faces; /backForward.faces";
18
19 /** *//**
20 * Application associate that contains navigation mappings loaded from
21 * configuration file(s).
22 */
23 private ApplicationAssociate associate = null;
24
25 /** *//**
26 * This constructor uses the current <code>Application</code> instance to
27 * obtain the navigation mappings used to make navigational decisions.
28 */
29 public NavigationHandleWithAuthImpl() {
30 super();
31 if (DEBUGLOG.isDebugEnabled()) {
32 DEBUGLOG.debug("Created NavigationHandler instance ");
33 }
34 // if the user is using the decorator pattern, this would cause
35 // our ApplicationAssociate to be created, if it isn't already
36 // created.
37 ApplicationFactory aFactory = (ApplicationFactory) FactoryFinder
38 .getFactory(FactoryFinder.APPLICATION_FACTORY);
39 aFactory.getApplication();
40 associate = ApplicationAssociate.getInstance(ConfigureListener
41 .getExternalContextDuringInitialize());
42 }
43
44 /** *//**
45 * 检查URL权限
46 *
47 * @param authList
48 * List<FunctionVo>
49 * @param uri
50 * String
51 * @return boolean
52 */
53 private boolean checkURL(List<FunctionVo> authList, String uri) {
54 if (authList == null) {
55 return false;
56 }
57 for (FunctionVo vo : authList) {
58 String authUri = vo.getUrl();
59 if (authUri != null && !authUri.equals("")) {
60 int index = authUri.indexOf("?");
61 if (index >= 0) {
62 authUri = authUri.substring(0, index);
63 }
64 }
65 if (uri.equals("/" + authUri)) {

