Слинг-фильтр для обертывания тела запроса - PullRequest
0 голосов
/ 25 июня 2018

Сценарий использования: мы разрабатываем сайт закрытой группы пользователей AEM, на котором пользователям необходимо будет отправлять формы, запускающие рабочие процессы.Поскольку пользователи проходят проверку подлинности, часть полезной нагрузки рабочего процесса должна включать пользователя, который инициировал форму.

Я рассматриваю для этого использование форм AEM, которые сохраняются на узлах под /content/usergenerated/content/forms/af/my-site, но пользователь не упоминается в полезной нагрузке (только пользователь службы).В этом случае есть два пользователя сервиса: workflow-service, выполняющий рабочий процесс, и fd-service, который обрабатывал обработку формы и первоначальное сохранение.Например, следующий код, вызываемый из шага рабочего процесса, сообщает 'fd-service'

workItem.getWorkflowData().getMetaDataMap().get("userId", String.class);

Чтобы обойти это ограничение,

Рабочий процесс, инициированный из публикации экземпляра AEM: Все экземпляры рабочего процессасоздается с использованием пользователя службы, когда из экземпляра публикации AEM отправляются адаптивные формы, интерактивные сообщения или письма.В этих случаях имя пользователя, вошедшего в систему, не фиксируется в данных экземпляра рабочего процесса.

Я добавляю сервлет фильтра для перехвата первоначальной отправки формы перед сервлетом AEM Forms с использованиемОболочка запроса для изменения тела запроса с добавлением исходного идентификатора пользователя.

С точки зрения форм, рабочих процессов и средств запуска. Это в основном настройка, которую я имею https://helpx.adobe.com/aem-forms/6/aem-workflows-submit-process-form.html

Я рассмотрел следующие ресурсы:

Вот код моей оболочки

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.wrappers.SlingHttpServletRequestWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.ServletInputStream;
import java.io.*;

public class FormSubmitRequestWrapper extends SlingHttpServletRequestWrapper {
String requestPayload;
private static final Logger log = LoggerFactory.getLogger(FormSubmitRequestWrapper.class);

public FormSubmitRequestWrapper(SlingHttpServletRequest slingRequest) {
    super(slingRequest);

    // read the original payload into the requestPayload variable
    StringBuilder stringBuilder = new StringBuilder();
    BufferedReader bufferedReader = null;
    try {
        // read the payload into the StringBuilder
        InputStream inputStream = slingRequest.getInputStream();
        if (inputStream != null) {
            bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            char[] charBuffer = new char[128];
            int bytesRead = -1;
            while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
                stringBuilder.append(charBuffer, 0, bytesRead);
            }
        } else {
            // make an empty string since there is no payload
            stringBuilder.append("");
        }
    } catch (IOException ex) {
        log.error("Error reading the request payload", ex);
    } finally {
        if (bufferedReader != null) {
            try {
                bufferedReader.close();
            } catch (IOException iox) {
                log.error("Error closing bufferedReader", iox);
            }
        }
    }
    requestPayload = stringBuilder.toString();
}

/**
 * Override of the getInputStream() method which returns an InputStream that reads from the
 * stored requestPayload string instead of from the request's actual InputStream.
 */
@Override
public ServletInputStream getInputStream ()
        throws IOException {

    final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(requestPayload.getBytes());
    ServletInputStream inputStream = new ServletInputStream() {
        public int read ()
                throws IOException {
            return byteArrayInputStream.read();
        }
    };
    return inputStream;
}
}

Вот мой фильтр

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.engine.EngineConstants;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


import javax.jcr.Session;
import javax.servlet.*;
import java.io.IOException;


@Component(service = Filter.class,
        immediate = true,

        property = {
                Constants.SERVICE_DESCRIPTION + "=Add the CUG userID to any UGC posts",
                EngineConstants.SLING_FILTER_SCOPE + "=" + EngineConstants.FILTER_SCOPE_REQUEST,
                Constants.SERVICE_RANKING + ":Integer=3000",
                EngineConstants.SLING_FILTER_PATTERN + "=/content/forms/af/my-site.*"
        })


public class DecorateUserGeneratedFilter implements Filter {

    private static final Logger log = LoggerFactory.getLogger(DecorateUserGeneratedFilter.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        final SlingHttpServletResponse slingResponse = (SlingHttpServletResponse ) response;
        final SlingHttpServletRequest slingRequest= (SlingHttpServletRequest) request;

        FormSubmitRequestWrapper wrappedRequest = new FormSubmitRequestWrapper(slingRequest);

        log.info("starting ConfirmAlumniStatus workflow");
        log.info(getCurrentUserId(slingRequest));

        chain.doFilter(wrappedRequest, slingResponse);
    }

    @Override
    public void destroy() {

    }

    public String getCurrentUserId(SlingHttpServletRequest request) {
        ResourceResolver resolver = request.getResourceResolver();
        Session session = resolver.adaptTo(Session.class);
        String userId = session.getUserID();

        return userId;

    }

}

Когда POST-запросы обрабатываются этим фильтром, я получаю сообщение об ошибке ниже, в котором указано, что тело запроса имеетуже прочитано.Похоже, что рейтинг фильтра может быть недостаточно высоким.

25.06.2018 13: 11: 13.200 ОШИБКА [0: 0: 0: 0: 0: 0: 0: 1 [1529946669719] Служба POST /content/forms/af/my-site/request-access/jcr:content/guideContainer.af.internalsubmit.jsp HTTP / 1.1] org.apache.sling.engine.impl.SlingRequestProcessorImpl service: UncaughtБрошенный java.lang.IllegalStateException: данные запроса уже были прочитаны в org.apache.sling.engine.impl.request.RequestData.getInputStream (RequestData.java:669) в org.apache.sling.engine.impl.SlingHttpServletRequestInream.get(SlingHttpServletRequestImpl.java:292) в javax.servlet.ServletRequestWrapper.getInputStream (ServletRequestWrapper.java:136) в my.site.servlets.FormSubmitRequestWrapper. (FormSubmitRequest..java: 75) в org.apache.sling.engine.impl.filter.AbstractSlingFilterChain.doFilter (AbstractSlingFilterChain.java:68) в org.apache.sling.engine.impl.filter.AbstractSlingFilterChain.doFilter (AbstractSlingFilterChain.java:73) в org.apache.sling.engine.impl.filter.AbstractSlingFilterChain.doFilter (AbstractSlingFilterChain.java:73) в comc.doFilter (DynamicIncludeFilter.java:82) в org.apache.sling.engine.impl.filter.AbstractSlingFilterChain.doFilter (AbstractSlingFilterChain.java:68) в org.apache.sling.engine.impl.debug.RequestProilFFFЯва: 10

Я не думаю, что рейтинг сервиса работает.Когда я просматриваю http://localhost:4502/system/console/status-slingfilter, мой фильтр отображается как показано.Судя по другим перечисленным фильтрам, я думаю, что крайний левый номер - это рейтинг фильтра.По какой-то причине мой фильтр имеет рейтинг 0, хотя я установил как service.ranking = 700

0: class my.site.servlets.DecorateUserGeneratedFilter (id: 8402, property: service.ranking = 700);называется: 0;время: 0 мс;время / вызов: -1 мкс

Обновление: мне удалось исправить ранг фильтра, в результате чего значение 700 все еще дало исключение IllegalStateException.Если сделать 3000, то эта проблема исчезнет.Но когда request.getInputStream () вызывается из моей оболочки.Возвращает ноль.

Ответы [ 3 ]

0 голосов
/ 26 июня 2018

То, что вы пытаетесь сделать, может быть простым маршрутом, но не может быть ориентировано на будущее для новых выпусков AEM.

Вам нужен полный контроль над тем, как запускается ваш рабочий процесс!:

  1. В ваших формах должно быть поле, содержащее путь рабочего процесса (и, возможно, другую информацию, необходимую для этого рабочего процесса)
  2. Создайте пользовательский сервлет, в который будут публиковаться ваши формы.
  3. В этом сервлете обрабатываются все опубликованные пользователем значения (из формы).Но особенно запомните предполагаемый путь рабочего процесса и запустите его, используя API рабочего процесса.

Таким образом, вам не нужно связываться с программами запуска, и ваши рабочие процессы запускаются пользователями с использованием их идентификатора пользователя..

Надеюсь, это поможет.

0 голосов
/ 29 июня 2018

, если вы ищете пример кода:

      @SlingFilter(order = 1)
    public class MyFilter implements Filter {

@Override
public void init(FilterConfig filterConfig) throws ServletException {
    return;
}

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
        FilterChain filterChain) throws IOException, ServletException {

    ServletRequest request = servletRequest;

    if (servletRequest instanceof SlingHttpServletRequest) {
        final SlingHttpServletRequest slingRequest = (SlingHttpServletRequest) servletRequest;
            request = new SlingHttpServletRequestWrapper(slingRequest) {
              String userId = getCurrentUserId(slingRequest);
            };

    }

    filterChain.doFilter(request, servletResponse);
}

@Override
public void destroy() {
    return;
}
0 голосов
/ 26 июня 2018

Правильная идея, неправильное местоположение.

Краткий ответ: когда вы реализуете SlingHttpServletRequestWrapper, он обеспечивает обработку вызовов по умолчанию для исходного SlingHttpServletRequest, если вы добавляете параметр на лету, что вы хотитедля этого нужно убедиться, что методы, взаимодействующие с параметрами, переопределены, так что вы можете быть уверены, что ваш метод добавлен.Поэтому при инициализации вызовите исходную карту параметров, скопируйте эти элементы в новую карту, которая содержит ваши собственные значения.

Затем переберите все методы, которые будут запрашивать эти значения

getParameter(String)
getParameterMap()
getParameterNames()
getParameterValues(String)

Don 'Прикоснитесь к InputStream, он уже обработан для получения любых параметров, которые передаются.

Кроме того, это один из двух способов обработки этого типа сценария использования, другой вариант - использовать SlingPOSTProcessorsкак задокументировано https://sling.apache.org/documentation/bundles/manipulating-content-the-slingpostservlet-servlets-post.html

, которое позволяет вам определять, что записывается в хранилище, и изменять данные, чтобы включать, как и в вашем случае, дополнительное поле.

...