2011-08-04 55 views
1

我有這種安全性要求,其中用戶輸入該URL流被創建,然後如果用戶故意改變roomId當輸入一個URL這樣彈簧Webflow的 - 端流和執行快照

http://webserver.com/someapp/test/test-flow?roomId=12345

參數一些安全過濾器將檢查用戶是否有權訪問該房間,特別是如果訪問用戶可以繼續進行訪問,但是如果不是,流程必須終止,並且希望移除所有流程快照(如果存在多個)。因此,代碼就像是從過濾器這樣

提取物:

public void doFilter(ServletRequest request, ServletResponse response, 
    FilterChain chain) throws IOException, ServletException { 
HttpServletRequest req = (HttpServletRequest) request; 
HttpServletResponse resp = (HttpServletResponse) response; 
String roomId = req.getParameter("roomId"); 
if (roomId != null) { 
    if (currentUserHasAccess(roomId)) { 
    chain.doFilter(request, response); 
    } else { 
    flowExecutionManager.endFlow(); 
    return; 
    } 
} 
chain.doFilter(request, response); 
} 

現在flowExecutionManager是這樣

public class FlowExecutionManager extends FlowExecutionListenerAdapter { 
private RequestControlContext context; 
private FlowDefinition definition; 

@Override 
public void sessionCreating(RequestContext context, 
    FlowDefinition definition) { 
super.sessionCreating(context, definition); 
this.context = (RequestControlContext) context; 
this.definition = definition; 
} 

public void endFlow() { 
if (context != null && definition != null) { 
    context.removeAllFlowExecutionSnapshots(); 
    context.endActiveFlowSession(definition.getId(), definition.getAttributes()); 
    Flow flow = (Flow)definition; 
    flow.destroy(); 
} 
} 

在方法endFlow我已經嘗試切換這些行的順序

context.endActiveFlowSession(definition.getId(), definition.getAttributes()); 
context.removeAllFlowExecutionSnapshots(); 

無論這兩條線的順序如何,我總是會得到一個NPE(僅顯示一個extr棧跟蹤的行爲)

java.lang.NullPointerException 
at org.springframework.webflow.conversation.impl.SessionBindingConversationManager.getConversationContainer(SessionBindingConversationManager.java:140) 
at org.springframework.webflow.conversation.impl.SessionBindingConversationManager.getConversation(SessionBindingConversationManager.java:116) 
at org.springframework.webflow.execution.repository.support.AbstractFlowExecutionRepository.getConversation(AbstractFlowExecutionRepository.java:183) 
at org.springframework.webflow.execution.repository.support.AbstractFlowExecutionRepository.getConversation(AbstractFlowExecutionRepository.java:170) 
at org.springframework.webflow.execution.repository.impl.DefaultFlowExecutionRepository.removeAllFlowExecutionSnapshots(DefaultFlowExecutionRepository.java:156) 
at org.springframework.webflow.engine.impl.FlowExecutionImpl.removeAllFlowExecutionSnapshots(FlowExecutionImpl.java:431) 
at org.springframework.webflow.engine.impl.RequestControlContextImpl.removeAllFlowExecutionSnapshots(RequestControlContextImpl.java:230) 
at com.ags.blackcorp.finances.web.FlowExecutionManager.endFlow(FlowExecutionManager.java:26) 
at com.ags.blackcorp.finances.web.RoomFilter.doFilter(RoomFilter.java:100) 
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:237) 
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167) 
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084) 
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:378) 
at org.springframework.security.intercept.web.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:109) 
at org.springframework.security.intercept.web.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83) 
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390) 
at org.springframework.security.ui.ExceptionTranslationFilter.doFilterHttp(ExceptionTranslationFilter.java:101) 
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53) 
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390) 
at org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter.doFilterHttp(SecurityContextHolderAwareRequestFilter.java:91) 
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53) 
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390) 
at com.ags.blackcorp.security.ui.webapp.AfterAuthenticationProcess.doFilterHttp(AfterAuthenticationProcess.java:55) 
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53) 
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390) 
at org.springframework.security.ui.preauth.AbstractPreAuthenticatedProcessingFilter.doFilterHttp(AbstractPreAuthenticatedProcessingFilter.java:69) 
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53) 
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390) 
at org.springframework.security.context.HttpSessionContextIntegrationFilter.doFilterHttp(HttpSessionContextIntegrationFilter.java:235) 
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53) 
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390) 
at org.springframework.security.util.FilterChainProxy.doFilter(FilterChainProxy.java:175) 
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:237) 
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167) 
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084) 

顯然,線context.endActiveFlowSession(definition.getId(), definition.getAttributes());被結束流程,但我不能刪除執行快照。 任何想法我可能做錯了,或任何想法如何刪除執行快照。 關於最佳方法的任何想法。 提前感謝大家。

+0

爲什麼不在流啓動時將roomId存儲在流作用域變量中,然後忽略查詢參數之後?那麼你不需要關心用戶用它做什麼。 – Patrick

回答

0

試圖回答我的問題導致我下面的代碼:

public void endFlow() { 
if (context != null && definition != null) { 
    ExternalContextHolder.setExternalContext(contex.getExternalContext()); 
    context.removeAllFlowExecutionSnapshots(); 
    context.endActiveFlowSession(definition.getId(), definition.getAttributes()); 
    Flow flow = (Flow)definition; 
    flow.destroy(); 
    } 
} 

的ExternalContextHolder ...線避免了NPE和快照被刪除,flowSession它也被終止,但新的問題有興起

  • 爲什麼需要ExternalContextHolder?可以嗎?

下面是一些奇怪的(或者是正常的嗎?)行爲即時得到

想我已經在瀏覽器中TAB1另一個選項卡上e2s1開始流e1s1也e2s1,現在如果即時通訊和點擊「我的嚮導上的'next'按鈕我得到了e2s2(這是正確的),現在如果我刪除屬於e1s1的執行快照,它們將被移除而不會出現問題,但是如果轉到選項卡中的e2s2,並且點擊'previous'按鈕,那麼我可以返回到上一個快照,快照e2s1也不見了,我的意思是不應該刪除快照就像「每次執行」一樣。我已經測試了新的代碼來刪除流執行(使用FlowExecutionRepository類中的removeFlowExecution方法),但是現在我不會顯示它,相反,如果有人可以拋出一些指針,那就等於生病了。無論如何,如果沒有什麼表現出生病,請保持任何人對循環感興趣。

再次回答我的問題,希望這是最後的答案。

問:爲什麼需要ExternalContextHolder?

Ans:根據我的經驗,ExternalContextHolder可能是其中的一個,因此spring需要訪問(HttpServletRequest和HttpServletResponse)來處理請求發送的數據。最後從一個過濾器中刪除流程執行聽起來似乎是一個好主意,但webflow給了我們一個更好的方法,但我的意思是繼承FlowExecutionListenerAdapter,在這種情況下,我們重寫方法「void requestSubmitted(RequestContext context)」,這裏我檢查wheter或不是最新的用戶有權訪問roomId,然後我將調用方法endFlow(見下面的代碼)

public void endFlow(ExternalContext externalContext) { 
FlowUrlHandler handler = flowController.getFlowUrlHandler(); 
HttpServletRequest request = (HttpServletRequest) externalContext.getNativeRequest(); 
String stringKey = handler.getFlowExecutionKey(request); 
if (stringKey != null) { 
    FlowExecutorImpl flowExecutor = (FlowExecutorImpl) flowController.getFlowExecutor(); 
    FlowExecutionRepository repository = flowExecutor.getExecutionRepository(); 
    FlowExecutionKey key = repository.parseFlowExecutionKey(stringKey); 
    ExternalContextHolder.setExternalContext(externalContext); 
    FlowExecutionLock lock = null; 
    try{ 
    lock = repository.getLock(key); 
    }catch(NoSuchFlowExecutionException nsfee){  
    return; 
    } 
    lock.lock(); 
    try { 
    FlowExecution flowExecution = repository.getFlowExecution(key); 
    repository.removeFlowExecution(flowExecution); 
    } finally { 
    lock.unlock(); 
    } 
} 
} 

流量控制器(org.springframework.webflow.mvc.servlet.FlowController)被彈簧和注入其添加到我們的webflow配置文件中。 上面的代碼完全刪除流程執行,如果用戶試圖返回到前一個流程,可以說e1s1,那麼webflow自動創建一個新的流程執行e2s1,就這些。

如果ü要使用的過濾方法中,所有u需要在doFilter方法的這種

public void doFilter(ServletRequest request, ServletResponse response, 
    FilterChain chain) throws IOException, ServletException { 
HttpServletRequest req = (HttpServletRequest) request; 
HttpServletResponse resp = (HttpServletResponse) response; 
String roomId = req.getParameter("roomId"); 
ExternalContext externalContext = new ServletExternalContext(
    this.servletContext, req, resp); 
if (roomId != null) { 
    if (!currentUserHasAccess(roomId)) { 
     flowExecutionManager.endFlow(); 
     return; 
    } 
} 
chain.doFilter(request, response);  

this.servletContext其通過filterConfig.getServletContext()

0

我很抱歉,我不能獲得我沒有評論,因爲我沒有足夠的觀點去做,但是你對你的用例的實現似乎比它應該更復雜。正如@Patrick在你的問題的註釋部分所建議的那樣,爲什麼你不能將roomId參數存儲在flowScope var中?您可以在流文件中執行驗證或調用驗證方法,並執行成功或失敗驗證所需的轉換。您不必關心快照,因爲那些WebFlow工件本意是要被框架處理...