Wednesday, August 2, 2017

Preventing Duplicate Form Submission in Struts

Post/Redirect/Get design Pattern
PRG is a web development design pattern that prevents some duplicate form submissions.It supports bookmarksand the refresh buttons in a predictable manner that does not create duplicate form submission.




Duplicate form submission may occur in the following situations:-
-----------------------------------------------------------------
Using Refresh button
Using the browser back button to traverse back and resubmit form
Using Browser history feature and re-submit the form.
Malicious submissions to adversely impact the server or personal gains
Clicking more than once on a transaction that takes longer than usual



Preventing Duplicate Form Submission in Struts
-------------------------------------------------

What happens in form submission? Suppose you have a form named adduser.jsp and an Action named saveUser.do.
So, on clicking submit in the adduser.jsp page, struts finds the mapping saveUser.do and redirect to this url.
So, in the browser url you will find /app/saveUser.do.
And when you click on refresh same url is called and same form is submitted again.



Struts provides several ways to protect this.
--------------------------------------------

1. HTTP redirect after form submission
2. using TOKEN



1. HTTP redirect after form submission
--------------------------------------

Suppose form submission result is shown in a page called success.jsp. So, if redirect is set true in forward
of action in struts.config URL in the URL bar becomes /app/success.jsp. So, if you refresh on again the
success.jsp is called not the /app/saveUser.do. So, in this way we can protect against refresh.

Limitation :this does not protect against goint to back button of browser and submit the form again.


usage :

<forward name="add" path="/add.jsp" redirect="true"/>



2. Using TOKEN
-----------------

This method generates a Token using session id, current time and messagediagest and save this token to session.
The action responsible for rendering the form,  save the token using saveToken() method. So, the session is saved
in session and a hidden field name token with the value is set to html form. If you view the source of html form
page, you will find the hidden form as follows

<input type="hidden" name="org.apache.struts.taglib.html.TOKEN"value="some value">


When client submit the form this hidden field is also submitted.
Struts check the two TOKEN (token from session and token submitted). We can check the two token using
isTokenValid() method.
If they are equal, this method returns true and the form is submitted for the first time.
If not equal then it is duplicate form submission. Checking code is shown below:-



if(isTokenValid(request))
resetToken(request);
else{
request.setAttribute("prg-error","Duplicate Form Submission");
return mapping.findForward("error");
}

resetToken() method is used to clear the Token set for this action. Because if you have multiple form you must clear the Token. Otherwise for new form, you will always find duplicate form submission error.

Suppose action addUser renders adduser.jsp page. So, you have to save token in addUser corresponding class by calling saveToken(request) method. You should validate this token in the submit action which is saveUser.do here.




implementation
--------------
empform.jsp
-----------

<html>
<head>

<title>Add an Employee</title>
</head>
<body>
<%@ taglib uri="/WEB-INF/struts-html.tld"  prefix="html"%>
<%@ taglib uri="/WEB-INF/struts-bean.tld"   prefix="bean"%>

<html:form action="/dispatchEmp">
Select Operation to be performed
<html:select property="method">
<html:option value="addUser">Add</html:option>
<html:option value="update">Update</html:option>
<html:option value="delete">Delete</html:option>
<html:option value="read">Find</html:option>
<html:option value="showAll">View All Records</html:option>
</html:select>

<html:submit value="submit"/>
</html:form>

</body>
</html>

add this method in EmpDispatchAction
---------------------------

public ActionForward addUser(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
saveToken(request);
return mapping.findForward("add-user");
}



addemp.jsp
-----------

<html>
<head>

<title>Add an Employee</title>
</head>
<body>
<%@ taglib uri="/WEB-INF/struts-html.tld"  prefix="html"%>
<%@ taglib uri="/WEB-INF/struts-bean.tld"   prefix="bean"%>

<html:form action="/dispatchEmp?method=create">

<bean:message key="form.empid"/>
<html:text property="empid" />

<bean:message key="form.ename"/>
<html:text property="ename" />

<bean:message key="form.basic"/>
<html:text property="basic" />

<html:submit  value="add"/>
</html:form>

</body>
</html>



code in EmpDispatchAction
----------------------------

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

DAOUtil.dataSource=getDataSource(request);

if(DAOUtil.dataSource != null)
System.out.println("data source found ");

String result="";
EmpBeanForm empForm= (EmpBeanForm)form;
Emp e= new Emp();
e.setEmpid(empForm.getEmpid());
e.setEname(empForm.getEname());
e.setBasic(empForm.getBasic());

if(isTokenValid(request))
{
resetToken(request);
EmpService service= new EmpService(EmpDaoFactory.getEmpDAO());
Emp e1 = service.createEmp(e);

if(e1 != null)
result="add";

}
else{
request.setAttribute("prg-error","Duplicate Form Submission");
result="error";
}
System.out.println("result "+result);
return mapping.findForward(result);
}

configuration in struts-config.xml
----------------------------------

<action path="/dispatchEmp"
   type="mvc.EmpDispatchAction"
   name="empBean"
   scope="request"
    input="/empform.jsp"
    parameter="method">
    <forward name="add-emp" path="/add-emp.jsp" />
   <forward name="add" path="/add.jsp" redirect="true"/>
   <forward name="viewAll" path="/viewAllEmp.jsp"/>  
   <forward name="error" path="/error.jsp" />
</action>

No comments:

Post a Comment