我有这种安全要求,用户输入这样的网址
http://webserver.com/someapp/test/test-flow?roomId=12345
当输入该URL时,流程被创建,然后如果用户故意更改roomId参数,某些安全过滤器将检查用户是否有权访问该房间,如果有访问权限,则用户可以继续,但如果不是,则必须终止流程并且希望删除所有流快照(如果存在多个)。所以代码就像这样
从过滤器中提取:
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(仅显示堆栈跟踪的摘录)
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 :(得分: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也被终止了,但是出现了新的问题
下面是一些奇怪的(或者是正常的?)行为即将到来
假设我已经在浏览器tab1中启动了流e1s1,在另一个选项卡中启动了e2s1,现在如果我在e2s1上并点击我的向导上的“下一步”按钮我得到e2s2(这是正确的),现在如果我删除执行快照属于e1s1,它们被删除没有问题,但如果去e2s2的选项卡,我点击'上一步'按钮,所以我可以返回到以前的快照,快照e2s1也消失了,我的意思是不应该删除快照就像是“执行”。我已经测试了新代码以删除流程执行(使用类FlowExecutionRepository中的方法removeFlowExecution)但是现在我不会显示它,而是等待有人可以抛出一些指针。无论如何,如果没有任何表现,那就是让任何人对循环感兴趣。
我再次回答我的问题,希望这是最后的答案。
问:为什么需要ExternalContextHolder?
Ans:根据我的经验,可能还有其他一些东西,所以Spring需要访问(HttpServletRequest和HttpServletResponse)来处理从谁做的请求发送的数据。
最后从过滤器中删除流程执行可能听起来不错,但是webflow给了我们一个更好的方法,我的意思是子类化FlowExecutionListenerAdapter,在这种情况下我们覆盖了方法“void requestSubmitted(RequestContext context)”,在这里我检查当前用户是否有权访问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();
}
}
}
flowController(org.springframework.webflow.mvc.servlet.FlowController)由spring注入,并在我们的webflow配置文件中添加。 上面的代码完全删除了流程执行,如果用户试图返回上一个流程,让我们说e1s1然后webflow自动创建一个新的流程执行e2s1,就是这样。
如果你想在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()
获得答案 1 :(得分:0)
对不起,我无法发表评论,因为我没有足够的分数这么做,但您对用例的实施似乎比应该更复杂。正如@Patrick在您的问题的评论部分所建议的,为什么您不能将roomId参数存储在flowScope var中?您可以在流文件中执行验证,也可以调用验证方法并为成功或失败的验证执行必要的转换。您不应该关心快照,因为那些是由框架处理的WebFlow工件...