aspose file tools*
The moose likes Struts and the fly likes Preventing multiple posts Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Frameworks » Struts
Bookmark "Preventing multiple posts" Watch "Preventing multiple posts" New topic
Author

Preventing multiple posts

Krishnappan Muthuraman
Greenhorn

Joined: Feb 16, 2004
Posts: 21
In order to avoid the multiple posts by the user, in the action class's execute method I am checking whether the token is valid or not. But always it is false. Why isTokenValid in Action class returns false always??

if (isTokenValid(request)) {
//process the request
return mapping.findForward("success");
} else {
return mapping.findForward("failure");
}

How to solve this one?
Junilu Lacar
Bartender

Joined: Feb 26, 2001
Posts: 5288
    
  10

Did you call saveToken()?

The flow is usually like this:

On initial request:
1. saveToken(request)
2. forward to JSP

When user submits form:
3. check if isTokenValid(request)
4. if true, process request then call resetToken(); otherwise, submission is not valid.

What's happening under the hood:
@1 Struts will generate a unique value (the token) and keep it in the session context
@2 When the JSP is rendered, Struts inserts the token as a hidden field
@3 The hidden field token is submitted along with the rest of the form and isValidToken() checks the value that came in with the current request against the value that was saved in the session context by the most recent saveToken() call. If the two token values match, the submission is valid.


Junilu - [How to Ask Questions] [How to Answer Questions]
Lasse Koskela
author
Sheriff

Joined: Jan 23, 2002
Posts: 11962
    
    5
FYI, I created an entry into our StrutsFaq based on Junilu's answer...


Author of Test Driven (2007) and Effective Unit Testing (2013) [Blog] [HowToAskQuestionsOnJavaRanch]
Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 5608
    
  15

Originally posted by Junilu Lacar:
Did you call saveToken()?

The flow is usually like this:

On initial request:
1. saveToken(request)
2. forward to JSP

When user submits form:
3. check if isTokenValid(request)
4. if true, process request then call resetToken(); otherwise, submission is not valid.


What's meant by "initial request"?


SCJA, SCJP (1.4 | 5.0 | 6.0), SCJD
http://www.javaroe.be/
Krishnappan Muthuraman
Greenhorn

Joined: Feb 16, 2004
Posts: 21
Step 1:
-------
In your jsp page add the token to the session and have a hidden field and store the same value

<%
String token = TokenProcessor.getInstance().generateToken(request);
session.setAttribute("org.apache.struts.action.TOKEN", token);
%>

<html:hidden property="org.apache.struts.taglib.html.TOKEN" value="<%=token%>"/>

Step 2:
--------
In action class execute method addd below lines..

if (isTokenValid(request)) {
resetToken(request);
//process the request..
} else {
return mapping.findForward("failure");
}

Then it works!!!. This is actcally a round about way.

But why savetoken(request) doesn't work??
Junilu Lacar
Bartender

Joined: Feb 26, 2001
Posts: 5288
    
  10

Step 1:
-------
In your jsp page add the token to the session and have a hidden field and store the same value

<%
String token = TokenProcessor.getInstance().generateToken(request);
session.setAttribute("org.apache.struts.action.TOKEN", token);
%>


This is pretty much what saveToken() and Struts does only you're choosing to do it yourself in the JSP which, IMO, is a bad design choice.

This is actcally a round about way.

Yes, it is. And unnecessary.

But why savetoken(request) doesn't work??

saveToken() works, I use it all the time. You're probably doing something wrong but it's hard to tell without any code to diagnose. Post the code that you think should work.
[ August 04, 2004: Message edited by: Junilu Lacar ]
Junilu Lacar
Bartender

Joined: Feb 26, 2001
Posts: 5288
    
  10

Originally posted by Roel De Nijs:
What's meant by "initial request"?


The "initial request" is made when the user clicks on a button or link (i.e. user submits a request) that will bring up the page that you want to protect from multiple submits. Assuming you are following the advice to Link Only to Actions, you can then call saveToken() before forwarding to the requested page. This causes Struts to insert the hidden token field in any html forms included in the response.
[ August 04, 2004: Message edited by: Junilu Lacar ]
Krishnappan Muthuraman
Greenhorn

Joined: Feb 16, 2004
Posts: 21
How will you set the value of the hidden field? I used this approach because saveToken(request) doesn't return anything!. Do you know how to the hidden field?

<html:hidden property="org.apache.struts.taglib.html.TOKEN" value="<%=token%>"/>

----Krishnappan Muthuraman
Junilu Lacar
Bartender

Joined: Feb 26, 2001
Posts: 5288
    
  10

Originally posted by Krishnappan Muthuraman:
How will you set the value of the hidden field?


You don't. Struts does it for you.

OK, since you won't post any code, I'll try to write some sample skeleton code and you can compare it with what you're doing :roll: . Caveat: this is off the top of my head and untested.


bethanapalli kumar
Greenhorn

Joined: Oct 29, 2004
Posts: 6
Hi
Our application is a State Based one...we have to allow user to submit form only once. We are using struts1.1,servlet2.3,jstl,jboss.

StrutsConfig.xml
-----------------

<form-beans>
<form-bean name="testForm" type="com.bluephant.form.TestForm" />
</form-beans>

<action-mappings>

<action path="/test" type="com.bluephant.form.TestPreAction" scope="session">
<forward name="success" path="/test.jsp" />
</action>

<action path="/test2"
type="com.bluephant.form.TestPostAction"
name="testForm"
validate="true"
input="/test.jsp"
scope="request">
<forward name="next" path="/test_next.jsp" />
</action>

TestPreAction
-------------
public ActionForward execute(ActionMapping mapping,ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {

saveToken(request);
return (mapping.findForward("success"));

}
TestPostAction
----------------
public ActionForward execute(ActionMapping mapping,ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {

if (isTokenValid(request)) {
resetToken(request);
saveToken(request);
//valid token process the form
return (mapping.findForward("next"));
}else{
MessageResources messages = getResources(request);
ActionErrors errors = new ActionErrors();
errors.add("org.apache.struts.action.GLOBAL_ERROR", new ActionError( "dvd.error.invalidToken" ) );
saveErrors( request, errors );
//duplicate submission
return (new ActionForward(mapping.getInput()));
}
test.jsp
---------
<html:form action="/test2.do" method="POST">

If i use browser back button once i submit form isTokenValid(request)) in TestPostAction always returns the true..... instead of false.....

it working fine if i use refresh button.
Suresh KC
Greenhorn

Joined: Mar 07, 2006
Posts: 1
That's because if the saveToken is not called before isTokenValid,
it will return false as there is no TOKEN set in the session.

How do you solve it? You have to have forward action whose job is to saveToken and forward you to the form.

Now when the submit button is pressed, the Action class's job is to check
by isValidToken().

If you do not use 2 actions or Forward to the form page, there will be problem in the first submission (thinks it is duplicate because it has no token) but subsequent duplicate submissions will be known.

One work around is to check if it is firstSubmission by checking for
org.apache.struts.taglib.html.TOKEN in the action class
if it is not set at all, that means it is not a duplicate form and should be allowed to run.
Clara Milanez
Greenhorn

Joined: Feb 05, 2010
Posts: 1

hi!
thanks for this post, helped me very much.
to test and understanding better, i printed in console the content of tokens before the test isTokenValid:
request.getSession().getAttribute("org.apache.struts.action.TOKEN"))
request.getParameter("org.apache.struts.taglib.html.TOKEN"))






 
With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.
 
subject: Preventing multiple posts