Início > Programação > Utilizando o SimpleCaptcha em um Aplicação JSF

Utilizando o SimpleCaptcha em um Aplicação JSF

De acordo com a Wikipedia:

CAPTCHA é um acrônimo da expressão “Completely Automated Public Turing test to tell Computers and Humans Apart” (teste de Turing público completamente automatizado para diferenciação entre computadores e humanos): um teste de desafio cognitivo, utilizado como ferramenta anti-spam, desenvolvido pioneiramente na universidade de Carnegie-Mellon.

Há várias implementações de CAPTCHA no mercado. Uma delas é o reCAPTCHA do Google. Tentei usar o reCAPTCHA em minha aplicação, mas logo esbarrei em problemas de proxy e percebi que os problemas que teria com a infraestrutura da minha empresa não compensariam o ganho.

Por isso, decidi utilizar o SimpleCaptcha, uma biblioteca Java que gera o par desafio/resposta do CAPTCHA. Vamos utilizar essa biblioteca para demonstrar como criar o CAPTCHA abaixo em uma aplicação JSF. Trata-se de um formulário simples com um captcha, um link para gerar outra imagem, um campo de input para digitar o texto da imagem e um link para salvar via ajax:

captcha

Primeiro, vamos criar um servlet que recebe as dimensões da imagem do captcha por parâmetro, cria o captcha, o insere na sessão para uso no ManagedBean e renderiza a imagem na response. Note o parâmetro “seed” passado na request e utilizado para compôr o nome da imagem gerada no cabeçalho da resposta. Voltaremos a ele quando estivermos explicando o ManagedBean:

import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import nl.captcha.Captcha;
import nl.captcha.noise.StraightLineNoiseProducer;

public class SimpleCaptchaServlet extends HttpServlet {

	@Override
	public void doGet(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
		// Dimensoes do captcha
		String sHeight = request.getParameter("height");
		String sWidth = request.getParameter("width");
		int height = Integer.parseInt(sHeight);
		int width = Integer.parseInt(sWidth);

		// Gera o captcha
		Captcha captcha = new Captcha.Builder(width, height).addText().
                addNoise(new StraightLineNoiseProducer()).addBorder().build();

		// Insere o captcha na sessao
		HttpSession session = request.getSession(true);
		session.setAttribute(Captcha.NAME, captcha);
		
		// Renderiza a imagem do captcha
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		BufferedImage image = captcha.getImage();
		ImageIO.write(image, "png", baos);
		baos.flush();
		String seed = request.getParameter("seed");
		response.setContentType("image/png");
		response.setContentLength(baos.size());
		response.setHeader("Content-Disposition", "inline; filename=captcha-" + seed + ".png");
		
		BufferedInputStream input = null;
		BufferedOutputStream output = null;
		InputStream is = new ByteArrayInputStream(baos.toByteArray());

		try {
			input = new BufferedInputStream(is);
			output = new BufferedOutputStream(response.getOutputStream());
			byte[] buffer = new byte[is.available()];
			int length;
			while ((length = input.read(buffer)) > 0) {
				output.write(buffer, 0, length);
			}
		} finally {
			if (output != null) {
				output.close();
			}
			if (input != null) {
				input.close();
			}
		}
	}
}

Lá no site do SimpleCaptcha há vários efeitos que você pode adicionar ao CAPTCHA utilizando a interface fluente da API do SimpleCaptcha, como background, borda, família de fonte e etc. Em seguida, vamos mapear esse servlet no web.xml:

    <servlet>
        <servlet-name>SimpleCaptchaServlet</servlet-name>
        <servlet-class>br.com.captcha.SimpleCaptchaServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>SimpleCaptchaServlet</servlet-name>
        <url-pattern>/simpleCaptchaServlet</url-pattern>
    </servlet-mapping>

O xhtml do formulário ficará como o abaixo. Note a chamada da servlet passando por parâmetro o “seed”, que comentaremos em seguida, a altura e a largura da imagem:

    <h:panelGroup id="panel" >
        <p:graphicImage value="/simpleCaptchaServlet?seed=${captchaFormMB.seed}&amp;height=50&amp;width=200" />
        <h:commandLink title="+ gerar outra">+ gerar outra
            <f:ajax execute="panel" listener="#{captchaFormMB.gerarOutraImagem}" event="click" render="panel"/>
        </h:commandLink>
        <p:inputText name="nome" value="#{captchaFormMB.resposta}" maxlength="5" />
    </h:panelGroup>

Agora, vamos analisar o ManagedBean desse formulário:

@ManagedBean
@ViewScoped
public class CaptchaFormMB {

	private double seed;

	private String resposta;

	public ContatoMB() {
		this.seed = Math.random();
	}

	public void salvar(AjaxBehaviorEvent event) {
		HttpSession session = (HttpSession) FacesContext.getCurrentInstance()
                  .getExternalContext().getSession(false);
		Captcha captcha = (Captcha) session.getAttribute(Captcha.NAME);
		if (!this.resposta.equals(captcha.getAnswer())) {
		    FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, 
                      "Erro na validacao do captcha", "Erro na validacao do captcha");
		      FacesContext.getCurrentInstance().addMessage("mensagem-sistema", msg);
		}
		this.resposta = "";
		this.seed = Math.random();
	}

	public void gerarOutraImagem(AjaxBehaviorEvent event) {
		this.resposta = "";
		this.seed = Math.random();
	}
}

O método “gerarOutraImagem” força, via ajax, a renderização de uma nova imagem de captcha. Aqui entra a questão da propriedade “seed”. Trata-se de um artifício para impedir que o navegador faça cache. Note que na implementação do servlet utilizamos esse parâmetro para compôr o nome do arquivo. O “seed” nada mais é que o resultado do método Math.random() do Java.

O método “salvar” recupera o CAPTHA que foi inserido na sessão pelo servlet e compara o texto da imagem com o valor informado pelo usuário. Caso os textos não coincidam, uma mensagem de erro é exibida.

Anúncios
  1. Nenhum comentário ainda.
  1. No trackbacks yet.

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

%d blogueiros gostam disto: