B/S通常我們的權限控制包括以下幾個方面:1,Web層訪問權限控制(包括URL級或Button/Link級);2,業務邏輯訪問控制,主要指業務邏輯中方法級的權限控制;3,數據訪問權限控制,主要指對Table, View的訪問控制,嚴格的控制會到Row級,甚至是Field級。
問題引入:
我們通常的系統中僅僅做了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,解決這一問題。先給出詳細的實現:
??1
public?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))?
{
?66
????????????????return?true;
?67
????????????}
?68
????????}
?69
????????return?false;
?70
????}
?71
?72
????/**?*//**
?73
?????*?Determine?the?next?view?based?on?the?current?view?
?74
?????*?(<code>from-view-id</code>
?75
?????*?stored?in?<code>FacesContext</code>),?<code>fromAction</code>?and
?76
?????*?<code>outcome</code>.
?77
?????*?
?78
?????*?@param?context
?79
?????*????????????The?<code>FacesContext</code>
?80
?????*?@param?fromAction
?81
?????*????????????the?action?reference?string
?82
?????*?@param?outcome
?83
?????*????????????the?outcome?string
?84
?????*/
?85
????public?void?handleNavigation(FacesContext?context,?String?fromAction,
?86
????????????String?outcome)?
{
?87
????????if?(context?==?null)?
{
?88
????????????String?message?=?Util
?89
????????????????????.getExceptionMessageString(Util.
?90
????????????????????????????NULL_PARAMETERS_ERROR_MESSAGE_ID);
?91
????????????message?=?message?+?"?context?"?+?context;
?92
????????????throw?new?NullPointerException(message);
?93
????????}
?94
????????if?(outcome?==?null)?
{
?95
????????????if?(DEBUGLOG.isDebugEnabled())?
{
?96
????????????????DEBUGLOG.debug("No?navigation?rule?found?for?outcome?"
?97
????????????????????????+?outcome?+?"and?viewId?"
?98
????????????????????????+?context.getViewRoot().getViewId()
?99
????????????????????????+?"?Explicitly?remain?on?the?current?view?");
100
????????????}
101
????????????return;?//?Explicitly?remain?on?the?current?view
102
????????}
103
????????CaseStruct?caseStruct?=?getViewId(context,?fromAction,?outcome);
104
????????ExternalContext?extContext?=?context.getExternalContext();
105
????????if?(caseStruct?!=?null)?
{
106
????????????Object?obj?=?context.getExternalContext().getSessionMap().get(
107
????????????????????Constant.LOGIN_INFO_KEY);
108
????????????List?authList?=?null;
109
????????????if?(obj?!=?null)?
{
110
????????????????authList?=?((LoginInfo)?obj).getAuthorityFunctionVoList();
111
????????????}
112
????????????String?uri?=?caseStruct.navCase.getToViewId().replace(".jsp",
113
????????????????????".faces");
114
????????????boolean?flag=true;
115
????????????if?(this.IGNORED_URI.indexOf(uri)?<?0)?
{
116
????????????????if?(authList?!=?null?&&?!this.checkURL(authList,?uri))?
{
117
????????????????????//?URI?is?invalid
118
????????????????????flag=false;
119
????????????????}
120
????????????}
121
122
????????????ViewHandler?viewHandler?=?Util.getViewHandler(context);
123
????????????Util.doAssert(null?!=?viewHandler);
124
125
????????????if?(caseStruct.navCase.hasRedirect())?
{
126
????????????????//?perform?a?302?redirect.
127
????????????????String?newPath?=?viewHandler.getActionURL(context,
128
????????????????????????caseStruct.viewId);
129
130
????????????????try?
{
131
????????????????????if?(DEBUGLOG.isDebugEnabled())?
{
132
????????????????????????DEBUGLOG.debug("Redirecting?to?path?"?+?newPath
133
????????????????????????????????+?"?for?outcome?"?+?outcome?+?"and?viewId?"
134
????????????????????????????????+?caseStruct.viewId);
135
????????????????????}
136
????????????????????extContext.redirect(newPath);
137
????????????????}?catch?(java.io.IOException?ioe)?
{
138
????????????????????String?message?=?"Redirect?to?"?+?newPath?+?"?failed.";
139
????????????????????ERRORLOG.error(message);
140
????????????????????throw?new?FacesException(message,?ioe);
141
????????????????}
142
????????????????context.responseComplete();
143
????????????????if?(DEBUGLOG.isDebugEnabled())?
{
144
????????????????????DEBUGLOG
145
????????????????????????????.debug("Response?complete?for?"?
146
????????????????????????????????????+?caseStruct.viewId);
147
????????????????}
148
????????????}?else?
{
149
????????????????UIViewRoot?newRoot?=?null;
150
????????????????if?(flag)?
{
151
????????????????????newRoot?=?viewHandler
152
????????????????????????.createView(context,?caseStruct.viewId);
153
????????????????}?else?
{
154
????????????????????newRoot?=?viewHandler.createView(context,
155
????????????????????????"/backForward.jsp");
156
????????????????}
157
????????????????context.setViewRoot(newRoot);
158
????????????????if?(DEBUGLOG.isDebugEnabled())?
{
159
????????????????????DEBUGLOG.debug("Set?new?view?in?FacesContext?for?"
160
????????????????????????+?caseStruct.viewId);
161
????????????????}
162
????????????}
163
????????}
164
????}
165
166
????/**?*//**
167
?????*?This?method?uses?helper?methods?to?determine?the?new?<code>view</code>
168
?????*?identifier.?Refer?to?section?7.4.2?of?the?specification?for?more?details.
169
?????*?
170
?????*?@param?context
171
?????*????????????The?Faces?Context
172
?????*?@param?fromAction
173
?????*????????????The?action?reference?string
174
?????*?@param?outcome
175
?????*????????????The?outcome?string
176
?????*?@return?The?<code>view</code>?identifier.
177
?????*/
178
????private?CaseStruct?getViewId(FacesContext?context,?String?fromAction,
179
????????????String?outcome)?
{
180
????????//?String?nextViewId?=?null;
181
????????String?viewId?=?context.getViewRoot().getViewId();
182
????????CaseStruct?caseStruct?=?null;
183
184
????????synchronized?(this)?
{
185
????????????caseStruct?=?findExactMatch(viewId,?fromAction,?outcome);
186
187
????????????if?(caseStruct?==?null)?
{
188
????????????????caseStruct?=?findWildCardMatch(viewId,?fromAction,?outcome);
189
????????????}
190
191
????????????if?(caseStruct?==?null)?
{
192
????????????????caseStruct?=?findDefaultMatch(fromAction,?outcome);
193
????????????}
194
????????}
195
????????return?caseStruct;
196
????}
197
198
????/**?*//**
199
?????*?This?method?finds?the?List?of?cases?for?the?current?<code>view</code>
200
?????*?identifier.?After?the?cases?are?found,?the?<code>from-action</code>?and
201
?????*?<code>from-outcome</code>?values?are?evaluated?to?determine?the?new
202
?????*?<code>view</code>?identifier.?Refer?to?section?7.4.2?of?the
203
?????*?specification?for?more?details.
204
?????*?
205
?????*?@param?viewId
206
?????*????????????The?current?<code>view</code>?identifier.
207
?????*?@param?fromAction
208
?????*????????????The?action?reference?string.
209
?????*?@param?outcome
210
?????*????????????The?outcome?string.
211
?????*?@return?The?<code>view</code>?identifier.
212
?????*/
213
214
????private?synchronized?CaseStruct?findExactMatch(String?viewId,
215
????????????String?fromAction,?String?outcome)?
{
216
????????//?String?returnViewId?=?null;
217
????????//?if?the?user?has?elected?to?replace?the?Application?instance
218
????????//?entirely
219
????????if?(null?==?associate)?
{
220
????????????return?null;
221
????????}
222
????????Map?caseListMap?=?associate.getNavigationCaseListMappings();
223
????????Util.doAssert(null?!=?caseListMap);
224
????????List?caseList?=?(List)?caseListMap.get(viewId);
225
????????if?(caseList?==?null)?
{
226
????????????return?null;
227
????????}
228
????????//?We've?found?an?exact?match?for?the?viewId.?Now?we?need?to?evaluate
229
????????//?from-action/outcome?in?the?following?order:
230
????????//?1)?elements?specifying?both?from-action?and?from-outcome
231
????????//?2)?elements?specifying?only?from-outcome
232
????????//?3)?elements?specifying?only?from-action
233
????????//?4)?elements?where?both?from-action?and?from-outcome?are?null
234
????????return?determineViewFromActionOutcome(caseList,?fromAction,?outcome);
235
????}
236
237
????/**?*//**
238
?????*?This?method?traverses?the?wild?card?match?List?(containing
239
?????*?<code>from-view-id</code>?strings?and?finds?the?List?of?cases?for?each
240
?????*?<code>from-view-id</code>?string.?Refer?to?section?7.4.2?of?the
241
?????*?specification?for?more?details.
242
?????*?
243
?????*?@param?viewId
244
?????*????????????The?current?<code>view</code>?identifier.
245
?????*?@param?fromAction
246
?????*????????????The?action?reference?string.
247
?????*?@param?outcome
248
?????*????????????The?outcome?string.
249
?????*?@return?The?<code>view</code>?identifier.
250
?????*/
251
????private?synchronized?CaseStruct?findWildCardMatch(String?viewId,
252
????????????String?fromAction,?String?outcome)?
{
253
????????CaseStruct?result?=?null;
254
255
????????//?if?the?user?has?elected?to?replace?the?Application?instance
256
????????//?entirely
257
????????if?(null?==?associate)?
{
258
????????????return?null;
259
????????}
260
261
????????Map?caseListMap?=?associate.getNavigationCaseListMappings();
262
????????Util.doAssert(null?!=?caseListMap);
263
????????TreeSet?wildcardMatchList?=?associate.getNavigationWildCardList();
264
????????Util.doAssert(null?!=?wildcardMatchList);
265
266
????????Iterator?iter?=?wildcardMatchList.iterator();
267
????????String?fromViewId;
268
????????List?caseList;
269
????????String?wcFromViewId?=?null;
270
????????while?(iter.hasNext())?
{
271
????????????fromViewId?=?(String)?iter.next();
272
????????????//?See?if?the?entire?wildcard?string?(without?the?trailing?"*"?is
273
????????????//?contained?in?the?incoming?viewId.?Ex:?/foobar?is?contained?with
274
????????????//?/foobarbaz
275
????????????//?If?so,?then?we?have?found?our?largest?pattern?match..
276
????????????//?If?not,?then?continue?on?to?the?next?case;
277
278
????????????if?(viewId.indexOf(fromViewId,?0)?==?-1)?
{
279
????????????????continue;
280
????????????}
281
????????????//?Append?the?trailing?"*"?so?we?can?do?our?map?lookup;
282
????????????wcFromViewId?=?fromViewId?+?"*";
283
????????????caseList?=?(List)?caseListMap.get(wcFromViewId);
284
285
????????????if?(caseList?==?null)?
{
286
????????????????return?null;
287
????????????}
288
289
????????????//?If?we've?found?a?match,?then?we?need?to?evaluate
290
????????????//?from-action/outcome?in?the?following?order:
291
????????????//?1)?elements?specifying?both?from-action?and?from-outcome
292
????????????//?2)?elements?specifying?only?from-outcome
293
????????????//?3)?elements?specifying?only?from-action
294
????????????//?4)?elements?where?both?from-action?and?from-outcome?are?null
295
296
????????????result?=?determineViewFromActionOutcome(caseList,?fromAction,
297
????????????????????outcome);
298
????????????if?(result?!=?null)?
{
299
????????????????break;
300
????????????}
301
????????}
302
????????return?result;
303
????}
304
305
????/**?*//**
306
?????*?This?method?will?extract?the?cases?for?which?a?<code>from-view-id</code>
307
?????*?is?an?asterisk?"*".?Refer?to?section?7.4.2?of?the?specification?for?more
308
?????*?details.
309
?????*?
310
?????*?@param?fromAction
311
?????*????????????The?action?reference?string.
312
?????*?@param?outcome
313
?????*????????????The?outcome?string.
314
?????*?@return?The?<code>view</code>?identifier.
315
?????*/
316
317
????private?synchronized?CaseStruct?findDefaultMatch(String?fromAction,
318
????????????String?outcome)?
{
319
????????//?String?returnViewId?=?null;
320
????????//?if?the?user?has?elected?to?replace?the?Application?instance
321
????????//?entirely
322
????????if?(null?==?associate)?
{
323
????????????return?null;
324
????????}
325
326
????????Map?caseListMap?=?associate.getNavigationCaseListMappings();
327
????????Util.doAssert(null?!=?caseListMap);
328
329
????????List?caseList?=?(List)?caseListMap.get("*");
330
331
????????if?(caseList?==?null)?
{
332
????????????return?null;
333
????????}
334
335
????????//?We?need?to?evaluate?from-action/outcome?in?the?follow
336
????????//?order:?1)elements?specifying?both?from-action?and?from-outcome
337
????????//?2)?elements?specifying?only?from-outcome
338
????????//?3)?elements?specifying?only?from-action
339
????????//?4)?elements?where?both?from-action?and?from-outcome?are?null
340
341
????????return?determineViewFromActionOutcome(caseList,?fromAction,?outcome);
342
????}
343
344
????/**?*//**
345
?????*?This?method?will?attempt?to?find?the?<code>view</code>?identifier?based
346
?????*?on?action?reference?and?outcome.?Refer?to?section?7.4.2?of?the
347
?????*?specification?for?more?details.
348
?????*?
349
?????*?@param?caseList
350
?????*????????????The?list?of?navigation?cases.
351
?????*?@param?fromAction
352
?????*????????????The?action?reference?string.
353
?????*?@param?outcome
354
?????*????????????The?outcome?string.
355
?????*?@return?The?<code>view</code>?identifier.
356
?????*/
357
????private?synchronized?CaseStruct?determineViewFromActionOutcome(
358
????????????List?caseList,?String?fromAction,?String?outcome)?
{
359
360
????????String?cncFromAction?=?null;
361
????????String?fromOutcome?=?null;
362
????????String?toViewId?=?null;
363
????????CaseStruct?result?=?new?CaseStruct();
364
????????int?size=caseList.size();
365
????????ConfigNavigationCase?cnc?=?null;
366
????????for?(int?i?=?0;?i?<?size;?i++)?
{
367
????????????cnc?=?(ConfigNavigationCase)?caseList.get(i);
368
????????????cncFromAction?=?cnc.getFromAction();
369
????????????fromOutcome?=?cnc.getFromOutcome();
370
????????????toViewId?=?cnc.getToViewId();
371
????????????if?((cncFromAction?!=?null)?&&?(fromOutcome?!=?null))?
{
372
????????????????if?((cncFromAction.equals(fromAction))
373
????????????????????????&&?(fromOutcome.equals(outcome)))?
{
374
????????????????????result.viewId?=?toViewId;
375
????????????????????result.navCase?=?cnc;
376
????????????????????return?result;
377
????????????????}
378
????????????}
379
????????}
380
????????for?(int?i?=?0;?i?<?size;?i++)?
{
381
????????????cnc?=?(ConfigNavigationCase)?caseList.get(i);
382
????????????cncFromAction?=?cnc.getFromAction();
383
????????????fromOutcome?=?cnc.getFromOutcome();
384
????????????toViewId?=?cnc.getToViewId();
385
????????????if?((cncFromAction?==?null)?&&?(fromOutcome?!=?null))?
{
386
????????????????if?(fromOutcome.equals(outcome))?
{
387
????????????????????result.viewId?=?toViewId;
388
????????????????????result.navCase?=?cnc;
389
????????????????????return?result;
390
????????????????}
391
????????????}
392
????????}
393
394
????????for?(int?i?=?0;?i?<?size;?i++)?
{
395
????????????cnc?=?(ConfigNavigationCase)?caseList.get(i);
396
????????????cncFromAction?=?cnc.getFromAction();
397
????????????fromOutcome?=?cnc.getFromOutcome();
398
????????????toViewId?=?cnc.getToViewId();
399
????????????if?((cncFromAction?!=?null)?&&?(fromOutcome?==?null))?
{
400
????????????????if?(cncFromAction.equals(fromAction))?
{
401
????????????????????result.viewId?=?toViewId;
402
????????????????????result.navCase?=?cnc;
403
????????????????????return?result;
404
????????????????}
405
????????????}
406
????????}
407
408
????????for?(int?i?=?0;?i?<?size;?i++)?
{
409
????????????cnc?=?(ConfigNavigationCase)?caseList.get(i);
410
????????????cncFromAction?=?cnc.getFromAction();
411
????????????fromOutcome?=?cnc.getFromOutcome();
412
????????????toViewId?=?cnc.getToViewId();
413
????????????if?((cncFromAction?==?null)?&&?(fromOutcome?==?null))?
{
414
????????????????result.viewId?=?toViewId;
415
????????????????result.navCase?=?cnc;
416
????????????????return?result;
417
????????????}
418
????????}
419
420
????????return?null;
421
????}
422
423
????/**?*//**
424
?????*?@author?robin
425
?????*/
426
????class?CaseStruct?
{
427
428
????????/**?*//**
429
?????????*?Field?viewId.
430
?????????*/
431
????????protected?String?viewId;
432
433
????????/**?*//**
434
?????????*?Field?navCase.
435
?????????*/
436
????????protected?ConfigNavigationCase?navCase;
437
????}
438
439
}
440
來看看其中的關鍵部分,149行起:
UIViewRoot?newRoot?=?null;

if?(flag)?
{?????
?????//當檢查URL通過時,使用CaseStruct,即faces-config.xml中的配置跳轉
????newRoot?=?viewHandler
????????.createView(context,?caseStruct.viewId);

}?else?
{??????
????//未通過URL檢查時,直接到權限不足頁面或你指定的頁面
????newRoot?=?viewHandler.createView(context,
????????"/backForward.jsp");
}
context.setViewRoot(newRoot);當然別忘了在faces-config.xml中加入自定義Application Navigation的配置,如下:
?1
<faces-config>
?2
????<application>
?3
????????<navigation-handler?id="navigationWithAuth">
?4
????????????com.***.framework.NavigationHandleWithAuthImpl
?5
????????</navigation-handler>
?6
????</application>
?7
?8
?9


10
11
</faces-config> 注意:
在NavigationHandler中,當發現檢查URL權限未能通過時,千萬不要直接去修改當前的那個CaseStruts,因為JSF自己會緩存整個跳轉的配置,以提高執行效率,請使用viewHandler.createView()來創建一個新CaseStruts,否則會發生跳轉不正常的情況。
posted on 2007-10-16 14:07
Robin's Programming World 閱讀(8694)
評論(6) 編輯 收藏 所屬分類:
Java