I'm making a Java webapp which uses the Spring 4 framework.
When a user makes any request, if the user is not logged in, I use an interceptor to store this request object inside the user's session. Afterwards I redirect the user to a login screen.
When the user succesfully logs in, I want the login controller to not return a model and view (for example, the homepage) but instead fetch the stored previous request from the session and "execute" it as if the user just launched that request.
I'm having some problems with filling in some variables:
public ModelAndView login(RedirectAttributes redirectAttributes)
{
... //Do login stuff.
HttpServletRequest previousRequest = (HttpServletRequest) httpServletRequest.getSession().getAttribute("previousRequest");
httpServletRequest.getRequestDispatcher(previousRequest.getServletPath()).forward(previousRequest, ????????);
//end of method, I must return a ModelAndView but I don't have any view, I just want the request to be forwarded??
return null; //???????????
}
When getting the request dispatcher, you need to give it an url. I used httpServletRequest.getServletPath() but I'm not sure if this is correct.
When forwarding, you need to give a request and response object. But I don't have the response object at this time. I could perhaps also store the response object just like I did with the request. Or is there any other way? What would happen if I supply the CURRENT reponse object instead of the PREVIOUS response object?
My method expects me to return a modelandview, but I don't have any. How can I tell Spring to stop doing its normal "modelandview" scheme and instead start working on the forwarding of the request?
The setup described above is impossible in Jboss. You cannot forward and pass an arbitrary request object, because the servlet container will display an error. The forward method is meant to forward the CURRENT request object that is begin processed by the container.
A possible strategy, although still not ideal, is to wrap the stored request together with a freshly incoming request, and override the important methods like getParameters()´ andgetAttribute()´ to use the stored request instead of the actual request. This is the way Spring security solves this.
It seems to be impossible to tell a servletcontainer to stop handling the current request and redirect or forward to an arbitrary request object you just so happen to have available in your servlet.
Related
I have a very simple JSP page where it has one search box and based off the input, in the search box, it will return a response with a submit button to get the following response.
I noticed that whenever I use request.getattribute("foo") in my servlet to retrieve some request it returns null due to the request ending so I looked at the answers on here and started using session.getattribute("foo") instead. However, now I am stuck having session variables responses being set and it is causing my view to have old session data that isn't suppose to be there so now I have to use session.removeAttribute("foo"), whenever, I don't want that particular response data to be shown.
Is there a better way to go about managing this instead of having to use session.getattribute("foo"), session.removeAttribute("foo") and session.setattribute("foo")?
You should work with request.getSession()
Returns the current session associated with this request, or if the request does not have a session, creates one.
Set an attribute:
request.getSession().setAttribute("foo")
And get attribute using:
request.getSession().getAttribute("foo")
It will be used in the context of the request and not effect other requests, so you don't need to remove attribute.
Read more in Servlets tutorial
Servlets provide an outstanding technical solution: the HttpSession API. This is a high-level interface that allows the server to "remember" a set of information relevant to a particular user's on-going transaction, so that it can retrieve this information to handle any future requests from the same user.
You can go for request.getparameter("foo") or request.setparameter("foo", obj)
This can be used for every request, and it will not add to your session variables and basically will not make your "session object heavy".
Java doc:
Request parameters are extra information sent with the request. For HTTP servlets, parameters are contained in the query string or posted form data.
I want to send values from jsp1.jsp to jsp2.jsp but redirect jsp1.jsp to jsp3.jsp . I used the following code in servlet for jsp1
response.sendRedirect("welcome1.jsp");
request.setAttribute("usern",user);
RequestDispatcher rd = request.getRequestDispatcher("afterlogin.jsp");
rd.forward(request,response);
but it keeps on giving this error "org.apache.jasper.JasperException: PWC6033: Error in Javac compilation for JSP".
you can use the possiblites of sessions in those case so you can access the parameter in jsp2 and redirect the jsp 1 to 3
https://www.javatpoint.com/servlet-http-session-login-and-logout-example
http://java.candidjava.com/tutorial/Servlet-Jsp-HttpSession-Login-logout-example.htm
You can use a HttpSession object as a user session, or use the ServletContext object for sharing global application information. Then use methods getAttribute (String attb) and setAttribute (String attb, String value) for sharing information within JSPs. The issue when you use a request is that the domain of the request is constraining you to use this information only when you receive this request.
You can also use JavaBeans to share information within JSPs
EDIT: Have you included your Java code inside a scriptlet? Using <% your code here %>
when you are using the sendRedirect function it will immediately redirect to that page it will not read next line code.
So according to your code your compiler is smart enough to check it so it is giving you an error.
please see below
1) SendRedirect ():
This method is declared in HttpServletResponse Interface.
Signature: void sendRedirect(String url)
1)In case of sendRedirect request is transfer to another resource to different domain or different server for further processing.
2)When you use SendRedirect container transfers the request to client or browser so URL given inside the sendRedirect method is visible as a new request to the client.
3)In case of SendRedirect call old request and response object is lost because it’s treated as new request by the browser.
4)SendRedirect is slower because one extra round trip is required because completely new request is created and old request object is lost.Two browser request required.
5)But in sendRedirect if we want to use we have to store the data in session or pass along with the URL.
2) Forward():
This method is declared in RequestDispatcher Interface.
Signature: forward(ServletRequest request, ServletResponse response)
1)When we use forward method request is transfer to other resource within the same server for further processing.
2)In case of forward Web container handle all process internally and client or browser is not involved.
3)When forward is called on requestdispather object we pass request and response object so our old request object is present on new resource which is going to process our request
4)Using forward () method is faster then send redirect.
5)When we redirect using forward and we want to use same data in new resource we can use request. setAttribute() as we have request object available.
more in : https://www.javatpoint.com/q/3577/difference-between-requestdispatcher-and-sendredirect
To keep it simple, the basic functions of my application are a search interface with a form for searching results. The app fetches these results via SOAP from another app.
On the search controller I need the ability to specify some parameters in the redirect that won't show up in the url of the results page and others that will. Here's an example of the what the redirect looks like:
return new ModelAndView(new RedirectView(/results?q=blah, true));
As you can see I need the q param to be included. But I also need other parameters that I don't want to show up on the results page url.
My app needs the ability to have multiple searches within one browser session. For example, having multiple tabs all searching at the same time. So the session object is abstracted to contain a map of session state objects. These hold state data for each search. A new session state is created each time a request is made to the search controller. This session state is then fetched by the results controller.
Our bookmarking process needs to be completely state free. So a person should be able to bookmark the results page url or copy and paste the url into a new tab or another browser. When the results url is executed, the results controller executes a new search.
My problem is this:
I need a way for the results controller to know whether the request is coming from a redirect in the search controller or from a (bookmark/copy & paste). That way it can grab the existing session state data or execute a new search. If I can pass a hidden parameter in the redirect from the search controller such as "requester", then I can use simple logic in the results controller to look for an existing session state or fire a new search.
Thanks
EDIT: What about passing data from one controller to the other without putting it in the url. Such as accessing model data passed from the search controller redirect in the results controller instead of the results view? Here's a constructor with the option to hide the model attributes.
/**
* Create a new RedirectView with the given URL.
* #param url the URL to redirect to
* #param contextRelative whether to interpret the given URL as
* relative to the current ServletContext
* #param http10Compatible whether to stay compatible with HTTP 1.0 clients
* #param exposeModelAttributes whether or not model attributes should be
* exposed as query parameters
*/
public RedirectView(String url, boolean contextRelative, boolean http10Compatible, boolean exposeModelAttributes)
Is there another way to pass data from one controller to the other?
An HTTP redirect response, normally designated by a 301 response code, contains a URI in its Location header that a client should request in order to find the specified resource. There's no way to tell the client anything else about the request to be made, only the URI it should request. Therefore only things that can go in the URI can be sent back in a redirect. You could make some guesses based on the Referer header, but that's no guarantee.
Have you considered just calling the second handler from your current handler? Something like this:
public ModelAndView currentHandler(...)
{
ModelAndView returnValue;
... stuff here...
if (make a decision)
{
returnValue = ... set the model and view as normal.
}
else
{
returnValue = ClassName.someOtherHandler( ... parameters ... );
}
return returnValue;
}
I'm using spring-security web authentication with spring-mvc with a custom authentication and all is well so far:
My problem is: /login loads a view with a fully-featured page, but now I have to provide authentication for iframe/popup format (e.g. for an authenticated bookmarklet), so loading a different view (or with different parameters).
I see two solutions that are not overcomplicated:
In my /login action, I have a way (unkown to me so far) to retrieve the original request and check it against a set of URLs that use the simpler view, then choose the matching view. => How do I retrieve this original request?
I make another login action/form, say /login/minimal, which also POSTs to the spring security URL /j_spring_security_check, but I need to implement the request storage/retrieval mechanism, so that the original request is performed after successful login. => I see this has something to do with SecurityContextPersistenceFilter, yet I don't know how to implement it or call it.
If I understand your question correctly, you're looking to vary the login page based on the original request string. Check out this forum post for accessing the original request url from the session. It's for an older version, but you should be able to use it to get started.
Edit I haven't had a chance to validate this, but it looks like the key changed between Acegi security and Spring Security 3. It looks like you can access it from session using the constants in the WebAttributes class. Effectively
//request is a HttpServletRequest object
SavedRequest savedRequest = (SavedRequest)request.getSession().getAttribute(WebAttributes.SAVED_REQUEST);
String url = savedRequest.getRequestURL();
For your first question:
there is a class org.springframework.security.web.authentication.WebAuthenticationDetails
It contains only the IP of the client and its Session, but
it has a method
protected void doPopulateAdditionalInformation(HttpServletRequest request) {}
I belive you could enhance this by subclassing and add the request url. -- But check first if the request is the request from the login form, or the "blocked" request.
Added
Chris Thompson posted an other part of the puzzle to answer your question:
He mentioned that the saved request can be obtained from the session:
//request is a HttpServletRequest object
SavedRequest savedRequest = (SavedRequest)request.getSession().getAttribute(WebAttributes.SAVED_REQUEST);
String url = savedRequest.getRequestURL();
So you can combine this, instead of enhanding the WebAuthenticationDetails you just need to read its already inclueded session.
#see Chris Thompson answer
In Java, the attribute field of a HttpServletRequest object can be retrieved using the getAttribute method:
String myAttribute = request.getAttribute("[parameter name]");
Where the HttpServletRequest attribute data is stored in a raw HTTP request? Is it in the body of the request?
For example, I'm trying to create a raw GET HTTP request that will be sent to my servlet using some client program. My servlet.doGet() method would be something like this:
public void doGet(HttpServletRequest request, HttpServletResponse response)
{
String myAttribute = request.getAttribute("my.username");
...
}
Where should I put the 'my.username' data in the raw HTTP request so that the 'myAttribute' String receives the value "John Doe" after the attribution?
Just to be clear as I think #Jon's answer doesn't make it perfectly clear. The values for getAttribute and setAttribute on HttpServletRequest are not present on what is actually sent over the wire, they are server side only.
// only visible in this request and on the server
request.getAttribute("myAttribute");
// value of the User-Agent header sent by the client
request.getHeader("User-Agent");
// value of param1 either from the query string or form post body
request.getParameter("param1");
To add to #gid's answer, attributes are not present in any way in the HTTP request as it travels over the wire. They are created (by your code) when processing the request. A very common use is to have a server set (aka create) some attributes and then forward to a JSP that will make use of those attributes. That is, an HTTP request arrives and is sent to a Servlet. The Servlet attaches some attributes. Additional server-side processing is done, eventually sending the page to a JSP, where the attributes are used. The response is generated in the JSP. The HTTP request and the HTTP response do not contain any attributes. Attributes are 100% purely server-side information.
When a single given HTTP request has completed, the attributes become available for garbage collection (unless they are persisted in some other location, such as a session). Attributes are only associated with a single request object.
I think what he is really asking is "how do I get parameteres into my program", not attributes. If that is the question, then send parameters in the GET request as part of the URL (after a question mark, http://myhost.com/myapp?name=joe&age=26) then retrieve them using request.getParameter("name") and request.getParameter("age"), or whatever you need.