[Logo] Mentawai Forum - Mentawai Web Framework
  [Search] Search   [Recent Topics] Recent Topics   [Members]  Member Listing   [Groups] Back to home page 
[Register] Register / 
[Login] Login 
Evitando ressubimissão na marra  XML
Forum Index -> Comentários Gerais Go to Page: 1, 2 Next 
Author Message
Lobo


[Avatar]

Joined: 23/01/2006 02:17:14
Messages: 841
Location: Fortaleza-CE
Offline

Caros vou postar o código que estou usando para evitar o lance do F5 , botão de reload do browser ressubimissão de form. fiz um lance meio "tenho que dar um jeito logo nisso" mas seria interessante algo elegante estilo mentawai.
Mas to sem tempo galera... tirei umas coisas na minha cabeça e outras achei soltas na internet mas tá funcionando que é uma beleza :]

Na action:
---------------------------------------------------------------------------

String token = input.getStringValue("token");
InputRequest ir = (InputRequest)input;
HttpSession session = ir.getRequest().getSession();
if (token != null){
if (session.getAttribute("token") == null){
session.setAttribute("token", token);
}
else{
if (session.getAttribute("token").equals(token)){
output.setValue("erro", "Mandar o form novamente ? isso não te pertence mais !!");
return ERROR;
}
else{
session.setAttribute("token", token);
}
}
}

===========================================



no jsp :
--------------------------------------------------------------------------
<%@ taglib prefix="lobo" uri="/WEB-INF/lobo.tld" %>

<lobo:TokenForm idSession="<%=request.getSession().getId()%>"/>

===========================================



Uma classe:


import java.security.MessageDigest;

public class TokenForm {

private String token;

public TokenForm(String idSession) throws Exception{
long systime = System.currentTimeMillis();
byte[] time = new Long(systime).toString().getBytes();
byte[] id = idSession.getBytes();
try{
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(id);
md5.update(time);
token = toHex(md5.digest());
}
catch(Exception e){
throw new Exception(e);
}
}

private String toHex(byte[] digest) {
StringBuffer buf = new StringBuffer();
for(int i = 0;i < digest.length;i++)
buf.append(Integer.toHexString(digest[i] & 0x00ff));
return buf.toString();
}

public String toString() {
return token;
}

public String getToken() {
return token;
}

public void setToken(String token) {
this.token = token;
}

}
=====================================


A classe que representa a tag:


package util;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;

import util.TokenForm;

public class TokenFormTag extends TagSupport
{
private String idSession;

public int doStartTag() throws JspException {
try{
TokenForm tokenForm = new TokenForm(idSession);
pageContext.getOut().print("<input type='hidden' name='token' value='"+ tokenForm +"'>");
}
catch(Exception e){
throw new JspException(e);
}
return SKIP_BODY;
}

public String getIdSession(){
return idSession;
}

public void setIdSession(String string) {
idSession = string;
}
}

==========================================

O TLD da tag


<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE taglib
PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>1.2</jsp-version>
<short-name>lobo</short-name>
<display-name>lobo</display-name>
<description>lobo</description>

<tag>
<name>TokenForm</name>
<tag-class>util.TokenFormTag</tag-class>
<body-content>JSP</body-content>
<attribute>
<name>idSession</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>

</taglib>

=========================================

Atenciosamente,
Hélio Frota

Atenciosamente,
Hélio Frota

Helio Frota
10+ Java Programmer
heliofrota.com

Member
Mentawai Developer
andre_guitar7


[Avatar]

Joined: 21/03/2006 12:03:21
Messages: 259
Location: Curitiba - PR
Offline

Cara, eu preciso muuuuuuuuuuuuuuuito disso!!
alexandre



Joined: 23/02/2006 11:48:04
Messages: 33
Location: São José dos Pinhais - PR
Offline

Uma solução que pensei agora seria colocar o System.currentTimeMillis(); em uma variavel no cookies ( é melhor do que ficar colocando em session no servidor, que pode comprometer a performance dependendo dos acessos)

e na action que escreve no banco o result do form faz assim :

Se não existir o cookie ou ele for diferente do que veio no input aceita o form e escreve a variavel no cookie.

Se for igual a que veio na input é porque é enviou duas vezes então deve-se aplicar sua logica.

Deve funcionar o que vocês acham ?
alexandre



Joined: 23/02/2006 11:48:04
Messages: 33
Location: São José dos Pinhais - PR
Offline

Funcionou !!


na action :

Code:
 if ( cookies.getAttribute("_time") != null ){
 			long a = 0;
 			long b = 0;
 			try{
 				a = Long.parseLong( (String) cookies.getAttribute("_time") );
 				b = Long.parseLong( input.getStringValue("_time") );
 			}catch (Exception e) {}			
 			if(a == b){
 				addError("Formulário já enviado anteriormente.");
 				return ERROR;	
 			}				
 		}
 		cookies.setAttribute("_time", input.getValue("_time"));
 


no form :
Code:
 <input type="hidden" name="_time" value="<%=System.currentTimeMillis()%>" />
 


Não sei como se pega em jstl o System.currentTimeMillis() mas assim funciona blz !!

Abraço.
Lobo


[Avatar]

Joined: 23/01/2006 02:17:14
Messages: 841
Location: Fortaleza-CE
Offline

não vou criticar de maneira alguma sua solução :]]

so quero saber se por acaso eu desabilitar cookies no browser ainda vai funcionar. se sim vou fazer refactor em todos os sistemas que estão usando mentawai.

mas foi massa a idéia é essa Alexandre, eu fiz um lance pra ter que consertar meu problema mas queria mesmo que todo mundo ajudasse já que o mentawai ta ajudando muita gente

Valeu cara

Atenciosamente,
Hélio Frota

Atenciosamente,
Hélio Frota

Helio Frota
10+ Java Programmer
heliofrota.com

Member
Mentawai Developer
alexandre



Joined: 23/02/2006 11:48:04
Messages: 33
Location: São José dos Pinhais - PR
Offline

Se a pessoa estiver com cookies desabilitado vai aceitar a resubimissão sim.

Acredito que ninguem desabilite os cookies, só se sua idéia é que possa haver um usuário mal intencionado, ai acho melhor mudar para session mesmo.

Mas é facil no meu código mesmo é só modificar onde tem cookies para session.

Acho que a melhor maneira de fazer isso é criar um filter e uma tag lib.
ia ser o menos doloroso pra mudar todos seus programas.
alexandre



Joined: 23/02/2006 11:48:04
Messages: 33
Location: São José dos Pinhais - PR
Offline

Com filtro fica assim :

Code:
 import org.mentawai.core.Action;
 import org.mentawai.core.Context;
 import org.mentawai.core.Filter;
 import org.mentawai.core.InvocationChain;
 import org.mentawai.i18n.LocaleManager;
 import org.mentawai.message.ClassMessageContext;
 import org.mentawai.message.DefaultMessage;
 import org.mentawai.message.FileMessageContext;
 import org.mentawai.message.MessageContext;
 import org.mentawai.message.MessageManager;
 
 public class SubmitFilter implements Filter{
 	
 	private MessageContext msgContext;
 	private String error = "Formulário já enviado.";
 	
 	public SubmitFilter(){
 		if (LocaleManager.isUseMasterForEverything()) {
             msgContext = new FileMessageContext(LocaleManager.getMaster(), "");
         } else {          
             msgContext = new ClassMessageContext(this.getClass());            
         }       
     }
 	
 	public SubmitFilter(String error){
 		this();
 		this.error = error;		
     }
 	
 
 	@SuppressWarnings("unchecked")
 	public String filter(InvocationChain chain) throws Exception {
 		Action action = chain.getAction();
 		Context cookies = action.getCookies();
 		
 		if ( cookies.getAttribute("_time") != null ){
 			String a = "";
 			String b = "";
 			try{
 				a = (String) cookies.getAttribute("_time");
 				b = action.getInput().getStringValue("_time");
 			}catch (Exception e) {}			
 			if(a.equals(b)){				
 				MessageManager.getErrors(action, true).add(new DefaultMessage(error, msgContext,null));				
 				return Action.ERROR;	
 			}				
 		}
 		cookies.setAttribute("_time", action.getInput().getValue("_time"));		
 		
 		return chain.invoke();
 	}
 	public void destroy() {	}
 }
 


ai no ApplicationManager colocase :

Code:
 .filter(new SubmitFilter())
 


saoj



Joined: 01/07/2005 09:59:17
Messages: 2846
Location: Rio de Janeiro, RJ
Offline

Excelente idéia, Alexandre.

Estou pensando aqui: Qual seria o lugar certo para esse filtro pegar a mensagem de erro ???

SubmitFilter_loc.i18n ?

ActionName_loc.i18n (acho que não!)

master_loc.i18n ???

Tua classe não ficou simples, e isso é contra a filosofia do Mentawai.

Precisamos de um filtro de validação geral, além do já existente filtro de validação de formulário.

Esse filtro vai prover maneiras simples de adicionar uma mensagem de erro/sucesso, como o BaseAction faz.

Quer tentar fazer Alexandre ???

Assim a sua classe extenderia esse filtro ao invés de implementar Filter e ficaria bem mais limpa do que está agora.






Sergio Oliveira

alexandre



Joined: 23/02/2006 11:48:04
Messages: 33
Location: São José dos Pinhais - PR
Offline

Humm blz, boa ideia.

Posso tentar fazer, mas ai só na segunda

Gostei da internacionalização em SubmitFilter_loc.i18n.

Abraço
Lobo


[Avatar]

Joined: 23/01/2006 02:17:14
Messages: 841
Location: Fortaleza-CE
Offline


Acho que a melhor maneira de fazer isso é criar um filter e uma tag lib.
ia ser o menos doloroso pra mudar todos seus programas 


Certo é isso que estou fazendo mas gostaria de saber se o oficial para o mentawai vai ser com cookies ou session

Pelo menos mais um problema resolvido pro mentawai. :]

Atenciosamente,
Hélio Frota


Atenciosamente,
Hélio Frota

Helio Frota
10+ Java Programmer
heliofrota.com

Member
Mentawai Developer
saoj



Joined: 01/07/2005 09:59:17
Messages: 2846
Location: Rio de Janeiro, RJ
Offline


Pode ser configurável para session ou cookie.

Se o cara desabilita os cookies a session funciona ?????

Nunca testei isso. Deveria funcionar via url rewrite mas tenho minhas dúvidas...

Session me parece mais seguro mesmo...

Sergio Oliveira

saoj



Joined: 01/07/2005 09:59:17
Messages: 2846
Location: Rio de Janeiro, RJ
Offline


Posso tentar fazer, mas ai só na segunda
 


Pô, vc que deu a idéia, que por sinal é boa, e agora está fazendo corpo mole pra fazê-la? A madrugada tá aí pra isso! Peque por excesso mas nunca por omissão.

Sergio Oliveira

Lobo


[Avatar]

Joined: 23/01/2006 02:17:14
Messages: 841
Location: Fortaleza-CE
Offline

Code:
 package filter;
 
 import org.mentawai.core.Action;
 import org.mentawai.core.Filter;
 import org.mentawai.core.Input;
 import org.mentawai.core.InvocationChain;
 import org.mentawai.core.Output;
 
 
 public class SubmissionFilter implements Filter{
 	
     public SubmissionFilter() {
     }
     
     public String filter(InvocationChain chain) throws Exception {
         Action action = chain.getAction();
         Input input = action.getInput();
         Output output = action.getOutput();
         
         String token = input.getStringValue("token");
         if (token != null){
 	      if (action.getSession().getAttribute("token") == null){
 		  action.getSession().setAttribute("token", token);
 	       }
 	       else{
 		    if (action.getSession().getAttribute("token").equals(token)){
 		        //A mensagem aqui eu deixei fixa.
                        output.setValue("erro", "....");
   		       return Action.ERROR;
 	           }
 		   else{
 		       action.getSession().setAttribute("token", token);
 		   }
 	      }
 	}
         
         return chain.invoke();
     }
     
     public void destroy() { }
 	
 }
 


-o método isTokenValid no struts tem comentado que recebe o token da sessão é so ver o código na classe TokenProcessor

-o Rifers citado em outro tópico parece usar veja o exemplo de formulário passo a passo que tem lá. Ao olhar o codigo fonte da página tem isso aqui

<input name="contid" type="hidden" value="fad5eee60ed96af2219ab6ee56e72210" />

Essa string maluca deve ser sem dúvida o id da sessão se não for é prima dela :]

no webwork tem isso escrito :
-TokenSessionStoreInterceptor, can provide much better logic for when invalid tokens are found.

-o Wicket também citado em outro tópico aqui, não encontrei exemplo rodando no site deles apenas screenshot dos exemplos :/ mas baixei o código fonte gorduroso do projeto e tem uma classe RequestCycle que não conheço mas to com suspeitas de que usa a mesma abordagem de token na sessão.

Atenciosamente,
Hélio Frota

Atenciosamente,
Hélio Frota

Helio Frota
10+ Java Programmer
heliofrota.com

Member
Mentawai Developer
velo


[Avatar]

Joined: 16/02/2006 13:33:54
Messages: 1197
Location: Jaraguá do Sul - SC
Offline

Isso foi parar dentro do menta?

Com que nome?


VELO

_____________________________________
Mentawai Developer
"When the only tool you have is a hammer, everything looks like a nail"
http://en.wikipedia.org/wiki/Golden_hammer
[Email] [MSN]
Lobo


[Avatar]

Joined: 23/01/2006 02:17:14
Messages: 841
Location: Fortaleza-CE
Offline

Cara mandei a solução caseira pro Rubem pra ver se ele ajeita pro menta mas não sei como ficou, até porque nem comentei nada no código, como sempre ando sem dormir.

Atenciosamente,
Hélio Frota

Atenciosamente,
Hélio Frota

Helio Frota
10+ Java Programmer
heliofrota.com

Member
Mentawai Developer
 
Forum Index -> Comentários Gerais Go to Page: 1, 2 Next 
Go to:   
Powered by JForum 2.1.6 © JForum Team