Spring WebFlow - конец потока и снимки выполнения - PullRequest
1 голос
/ 04 августа 2011

У меня есть такое требование безопасности, когда пользователь вводит URL-адрес, подобный этому

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());завершает поток, но я не могу удалить снимки выполнения.Любые идеи, что я мог бы делать неправильно, или любые идеи, как удалить моментальные снимки выполнения.Любая идея относительно лучшего подхода.Спасибо всем заранее.

Ответы [ 2 ]

0 голосов
/ 25 января 2016

Извините, я не могу комментировать, потому что у меня недостаточно очков, чтобы сделать это, но ваша реализация в вашем случае использования кажется намного более сложной, чем должна быть. Как подсказал @Patrick в разделе комментариев вашего вопроса, почему вы не можете просто сохранить аргумент roomId в переменной flowScope? Вы можете выполнить проверку в поточном файле или вызвать метод проверки и выполнить необходимые переходы для успешных или неудачных проверок. Вам не нужно заботиться о снимках, так как это артефакты WebFlow, предназначенные для обработки платформой ...

0 голосов
/ 05 августа 2011

Попытка ответить на мой собственный вопрос привела меня к следующему коду:

    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, снимки удаляются, а поток сеанса также завершается, однако возникли новые вопросы

  • зачем нужен ExternalContextHolder? это нормально?

Ниже приведено какое-то странное (или нормальное?) Поведение, которое я получаю

Предположим, я запустил поток e1s1 на вкладке браузера 1, а также e2s1 на другой вкладке, теперь, если я нахожусь на e2s1 и нажимаю кнопку «Далее» на моем мастере, я получаю e2s2 (это правильно), теперь, если я удаляю снимки выполнения которые принадлежат e1s1, они удаляются без проблем, но если перейти на вкладку, где находится e2s2, и я нажимаю кнопку «предыдущий», чтобы я мог вернуться к предыдущему снимку, снимок e2s1 также пропал, я имею в виду, что удаление снимка не должно быть чем-то «за» исполнение». Я проверил новый код для удаления выполнения потока (используя метод removeFlowExecution из класса FlowExecutionRepository), но сейчас я не буду его показывать, вместо этого я буду ждать, если кто-то может бросить несколько указателей. В любом случае, если ничего не обнаружится, я буду держать кого-то заинтересованным в петле.

Еще раз я отвечаю на мой вопрос, надеюсь, это последний ответ.

Q: зачем нужен ExternalContextHolder?

Ответ: согласно моему небольшому опыту, ExternalContextHolder, вероятно, помимо прочего, необходим, чтобы у Spring был доступ (HttpServletRequest и HttpServletResponse) к данным, отправляемым тем, кто выполняет запрос.

В конце концов, удаление flowexecution из фильтра может показаться хорошей идеей, но webflow дает нам еще лучший подход, я имею в виду создание подкласса FlowExecutionListenerAdapter, и в этом случае мы переопределили метод «void requestSubmitted (контекст RequestContext)», а здесь я проверьте, есть ли у текущего пользователя доступ к 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) добавляется пружиной и добавляется в наш файл конфигурации веб-потока. Приведенный выше код полностью удаляет выполнение потока, и если пользователь пытается вернуться к предыдущему потоку, скажем, e1s1, тогда веб-поток автоматически создает новое выполнение потока e2s1, и вот оно.

В случае, если вы хотите использовать подход фильтра, все, что вам нужно в методе doFilter, это this

    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 ()

...