Вызовите REST API с помощью jQuery со страницы JSF и получите текущий сеанс без файлов cookie. - PullRequest
0 голосов
/ 12 февраля 2020

У меня есть веб-приложение, которое использует JSF 2.3 для внешнего интерфейса и предлагает также API, который используется внешним интерфейсом с Jersey 2.29.1, работающим на сервере Tomcat 9.

Внешний интерфейс предлагает логин, который будет хранить аутентифицированного пользователя в @SessionScoped AuthenticationBean. Методы API должны использоваться только в том случае, если пользователь вошел в интерфейс.

@Path("/service")
public class ApiService {
  @GET
  @Path("/data")
  @Produces(MediaType.APPLICATION_JSON)
  public String loadData() {
    final AuthenticationBean authBean = CDI.current().select(AuthenticationBean.class).get();
    if (authBean != null && authBean.isLoggedIn()) {
      // Do business logic
    }
    else {
      throw new WebApplicationException(Response.Status.UNAUTHORIZED);
    }
  }
}

На странице JSF API используется с вызовом 'basi c' jQuery AJAX $.ajax() и обновляет некоторый визуальный контент на основе ответа JSON. URL, который я передаю на звонок AJAX: "#{request.contextPath}/api/service/data".

Все работает нормально, как и ожидалось, пока я не отключу куки в браузере. Если куки отключены, идентификатор сеанса добавляется в URL (вместо того, чтобы сохраняться в кулинарном сеансе ie) механизмом сервлета. Поэтому, если я не добавляю явно идентификатор сеанса в URL для вызова AJAX, у меня нет доступа к текущему сеансу в методе службы API, например, "#{request.contextPath}/api/service/data;jsessionid=#{session.id}", и поэтому я не могу проверить, вошел ли пользователь в систему или нет.

Мой вопрос сейчас заключается в том, нужно ли мне добавлять jsessionid вручную для каждого запроса AJAX или есть какая-либо другая «чистая» возможность передать идентификатор сеанса в методы службы? Или я должен получить доступ к сеансу любым другим способом в службе API?

Ответы [ 2 ]

0 голосов
/ 13 февраля 2020

Этот «ответ» не является ответом на ваш реальный вопрос, но объясняет, почему это никак не связано с JSF (в конце есть подсказка к ответу)

JSF - API и Джерси является реализацией API (JAX-RS). Они по сути являются взаимодополняющими технологиями и никак не связаны друг с другом. Это то же самое, что спросить, могу ли я использовать JPA и Джерси в одном приложении. Ваши настоящие вопросы как будто не имеют отношения к JSF. JSF использует механизм сеанса, предоставляемый механизмом сервлетов, так же, как это делает jax-rs.

Второе, что неясно, это то, что вы определяете как «внешний интерфейс» и что вы запускаете. JSF в стеке JavaEE - это интерфейсная технология. JSF имеет серверную часть, в которой вы объявляете компоненты (см. Каково определение «компонента» в JSF ), и когда генерируется html, они имеют клиентскую часть html / javascript / css дубликаты, которые взаимодействуют с сервером способом, указанным в спецификации JSF . «Компоненты» JSF сами по себе ничего не делают, если не поддерживаются «glue logi c» на сервере, который в свою очередь вызывает службы (см. JSF Controller, Service и DAO )

Это может теперь ясно, что

возможно ли, чтобы компонент JSF вызвал услугу Джерси по вызову AJAX?

является "расплывчатым" и наиболее вероятным из-за недостатка знаний о том, что / что делает JSF и как подходит Джерси (здесь Джерси должен быть «отдыхать» или jax-rs, если вы имеете в виду API), см. также Как реализовать службу JAX-RS RESTful в инфраструктуре JSF

  • Часть JSF Components html на стороне клиента связывается с сервером JSF-спецификацией c, поэтому

    1. Отдых там не нужен, чтобы клиентская сторона могла общаться с сервером (излишне)
    2. Попытка отдохнуть там делает вещи чрезмерно (чрезмерно) сложными и без реального преимущества
  • Если вы пытаетесь получить услугу JSF компоненты стороны для связи через REST

    1. Сторона сервера предназначена для взаимодействия со стороной клиента посредством JSF spe c для нее
    2. Они поддерживаются кодом, который в включай звонки в сервисы. В этом случае вы можете вызвать службу отдыха, базу данных или любую другую информацию
  • Если, как я подозреваю, вы хотите, чтобы $.ajax, не связанный с jsf, вызывал какую-либо службу отдыха
    1. Вы можете, но читайте Как реализовать сервис JAX-RS RESTful в JSF framework
    2. Вы можете сделать с ним что угодно, чтобы обновить клиентскую сторону html
    3. Вы даже можете обновить html, сгенерированный компонентами JSF
    4. При выполнении 3, NOT ожидать, что они будут работать все время, JSF не виноват здесь

Итак, после всего этого проблема с идентификатором сеанса не связана с jsf. У вас возникнет та же проблема при использовании обычного jsp или даже простого html, который инициировал сеанс.

HINT

Так что лучшим заголовком было бы "jsessionid в URL, не добавленном к ajax вызову в jquery". Я разместил это в поисковой системе и добавил site: stackoverflow. com: jsessionid в URL не добавлен к ajax вызову на jquery сайте: stackoverflow.com

Одним из результатов является дублирование вашего вопроса:

0 голосов
/ 13 февраля 2020

... явно добавляет идентификатор сеанса к URL-адресу ...

HttpServletResponse#encodeURL() выполняет именно эту задачу, см. также javado c (выделение мое):

Кодирует указанный URL-адрес, включая идентификатор сеанса, или, если кодирование не требуется, возвращает URL-адрес без изменений. Реализация этого метода включает в себя лог c для определения необходимости кодирования идентификатора сеанса в URL. Например, если браузер поддерживает файлы cookie или отслеживание сеанса отключено, кодировка URL не нужно.

Итак, в основном:

#{request.contextPath}#{response.encodeURL('/api/service/data')}

Этот же метод, кстати, делегирован ExternalContext#encodeResourceURL().

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

Джакартский сервлет : Это должно быть значение, возвращаемое javax.servlet.http.HttpServletResponse method encodeURL(url).

Итак, технически вы также можете сделать

#{request.contextPath}#{facesContext.externalContext.encodeResourceURL('/api/service/data')}

Но это немного менее удобно для ввода. Более того, использование #{request.contextPath} уже означает, что вы используете JSF поверх сервлетов, а не портлетов, поэтому использование #{response} должно быть вполне приемлемым. Возможно, вы захотите сделать его еще короче, определив пользовательский метод утилит в bean-объекте области приложения. Например,

#{functions.encodeURL('/api/service/data')}

@Named @ApplicationScoped
public class Functions {

    public String encodeURL(String uri) {
        ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
        return ec.getRequestContextPath() + ec.encodeResourceURL(uri);
    }

}
...