1

I have a web application which uses JSF 2.3 for the front end and offers also an API which is consumed by the front end with Jersey 2.29.1 running on a Tomcat 9 server.

The front end offers a login which will store the authenticated user in a @SessionScoped AuthenticationBean. The API methods should only be consumable if the user is logged in on the front end.

@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);
    }
  }
}

On the JSF page the API is consumed with a 'basic' jQuery AJAX call $.ajax() and updates some visual content based on the JSON response. The URL which I pass to the AJAX call is "#{request.contextPath}/api/service/data".

Everything works fine as expected, until I disable the cookies in the browser. If the cookies are disabled, the session ID is added to the URL (instead of being stored in a session cookie) by the servlet engine. So if I do not explicitly append the session ID to the URL for the AJAX call I have no access to the current session in the API service method, e.g. "#{request.contextPath}/api/service/data;jsessionid=#{session.id}" and therefore I can not check whether the user is logged in or not.

My question is now if I do have to add the jsessionid manually for every AJAX request or is there any other 'clean' possibility to pass the session ID to the service methods? Or do I have to access the session in any other way in the API service?

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
MichaelRS
  • 51
  • 3
  • I don't see anything related to jsf in this question... – Kukeltje Feb 12 '20 at 13:16
  • 1
    @Kukeltje Actually it is more on bringing JSF and Jersey together in one web application - is it possible for a JSF component to have called a Jersey service by an AJAX call? – MichaelRS Feb 12 '20 at 13:58

2 Answers2

0

... explicitly append the session ID to the URL ...

The HttpServletResponse#encodeURL() does exactly that task, see also javadoc (emphasis mine):

Encodes the specified URL by including the session ID, or, if encoding is not needed, returns the URL unchanged. The implementation of this method includes the logic to determine whether the session ID needs to be encoded in the URL. For example, if the browser supports cookies, or session tracking is turned off, URL encoding is unnecessary.

So, basically:

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

The same method is by the way delegated by ExternalContext#encodeResourceURL().

Return the input URL, after performing any rewriting needed to ensure that it will correctly identify an addressable resource in the current application.

Jakarta Servlet: This must be the value returned by the javax.servlet.http.HttpServletResponse method encodeURL(url).

So, technically you can also do

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

But this is a bit less convenient to type down. Moreover, using #{request.contextPath} already indicates that you're using JSF on top of servlets, not portlets, so using #{response} should be perfectly fine. You might want to make it yet shorter by defining a custom utility method in an application scoped bean. E.g.

#{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);
    }

}
Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
0

This 'Answer' is not an answer to your real question but an explanation on why this is in no way JSF related (at the end there is a hint though to an answer)

JSF is an api and Jersey is an implementation of an api (JAX-RS). They effectively are complementary technologies and have no relation to one another in any way. It's the same like asking can I use JPA and Jersey in one application. Your actual questions have like stated no relation to JSF whatsover. JSF uses the session mechanism provided by the servlet engine, just like jax-rs does.

The second thing that is unclear is what your definition of 'front-end' is and where you run what. JSF in the JavaEE 'stack' is a front-end technology. JSF has a server side part in which you declare the components(See What is the definition of "component" in JSF) and when the html is generated they have client side html/javascript/css counterparts which communicate with the server in a way that is specified in the JSF specs. JSF 'components' by themselves do nothing if not backed by 'glue logic' on the server that in turn calls services (See JSF Controller, Service and DAO)

It might by now be clear that

is it possible for a JSF component to have called a Jersey service by an AJAX call?

is 'vague' and most likely given by your lack of knowledge of what the JSF is/does and how Jersey fits in (Jersey should be 'rest' here or jax-rs if you mean the api), See also How to implement JAX-RS RESTful service in JSF framework

  • JSF Components' html part on the client side communicates with the server in a JSF specific way, so

    1. Rest is not needed there to get the client-side to communicate with the server (superfluous)
    2. Trying to get rest in there makes things overly (overly) complex and without a real advantage
  • If you are trying to get the JSF server side components to communicate via REST

    1. The server side is for interaction with the client side by means of the JSF spec for it
    2. They are backed by code that in turn calls services. In this you can call a rest service, database or whatever
  • If, like I suspect, you want a non-jsf related $.ajax to call some rest service
    1. You totally can, but read How to implement JAX-RS RESTful service in JSF framework
    2. You can do anything with it to update the client side html
    3. You can even update the html generated by JSF components
    4. When doing 3, do NOT expect them to still work al the time, JSF is not to blame here

So after all this, your session id problem is not a jsf related problem. You'd have the same problem when using plain jsp or even plain html that has triggered a session.

HINT

So a better title would have been "jsessionid in url not added to ajax call in jquery" I posted this one in a search engine and added site:stackoverflow.com: jsessionid in url not added to ajax call in jquery site:stackoverflow.com

One of the results is effectively a duplicate of your question:

Kukeltje
  • 12,223
  • 4
  • 24
  • 47
  • Hmm, that's a pretty different answer :) The dupe you found there does unfortunately not tell anything about the `HttpServletResponse#encodeURL()`. By the way, I have one more thing to add to your "use REST in JSF" verdict, the OP is basically violating the "S" part of REST by forcing it to use sessions ... – BalusC Feb 12 '20 at 21:29
  • @BalusC: Maybe because of a certain 'vagueness' in the question. The answer I referred to does not need to `HttpServletResponse#encodeUrl()` that since it suggests to take it from the client side where it is in the url. Hence a 'not jsf related' question. Using the content of the link in the 'hint' I also found some more concrete links with code. The fact that you **can** solve it with JSF (or facelets/el/cdi since you might also just be able to inject the servletcontext and not use the FacesContext?) is prove of the fact that it is still very useful ;-) – Kukeltje Feb 12 '20 at 21:44
  • @BalusC: Correct about the S part, but don't many user of the 'modern' hyped framework do this, don't they? At least I see some do this. But compliments for your answer. Creative and proof of great knowledge on your side – Kukeltje Feb 12 '20 at 21:46
  • @Kukeltje Sorry, you are right - the better question would have been your proposal... – MichaelRS Feb 13 '20 at 07:23