Início > programação, programação JSF > Como adicionar Captcha na aplicação JSF – solução com Recaptcha

Como adicionar Captcha na aplicação JSF – solução com Recaptcha

Um problema muito sério em aplicações que possuem acesso aberto na internet é o uso de softwares automatizados que enviam inúmeras requisições seguidas, normalmente com a pretensão de gerar spam, diminuindo o desempenho de sistemas e gerando prejuízo às empresas.

A técnica mais utilizada para evitar esse problema é o emprego de imagens com letras distorcidas, que em alguns casos pode ter a adição de uma seqüência obscurecida das letras ou dos dígitos que aparecem na tela. O objetivo é evitar o uso de robôs, já que eles não conseguem fazer a leitura de imagens. Essa solução é conhecida como Captcha (da sigla Completely Automated Public Turing test to tell Computers and Humans Apart) e embora tenha recebido esse nome, é visto como um Teste de Turing reverso, uma vez que é administrado pelo computador e não por humanos.

No meus testes em JSF consegui utilizar as soluções do Tomahawk, do PrimeFaces, do JCaptcha e do Recaptcha. Todos são muitos simples de adicionar à aplicação, mas o Tomahawk  e o JCaptcha integrado ao JSF usam, para fazer a validação, um atributo em escopo de sessão com o valor da chave, o que muitas vezes não é desejado a nível de arquitetura. Já o PrimeFaces tem como base o Recaptcha da Google, mas a maioria dos desenvolvedores (eu me incluo entre eles) usa o RichFaces como solução de biblioteca de interface rica, tornando-se impensável colocar o PrimeFaces na aplicação apenas para ter o componente Captcha.

Por fim, meu último teste foi o Recaptcha, da Google. Vamos às vantagens da solução:

  1. Não utiliza a chave como atributo de sessão para validar a imagem;
  2. Ajuda a digitalizar livros e jornais (no momento estão sendo digitalizadas edições do The New York Times e livros do Google Books);
  3. É acessível para deficientes visuais;
  4. É popular: empresas como Facebook e TicketMaster utilizam;
  5. Tem compatibilidade com várias linguagens e aplicações.

Obviamente que nem tudo são flores. As desvantagens são:

  1. O serviço da Google está na web, portanto se ele cair (pouco provável), ou se o host onde a aplicação Java está não conseguir comunicação com ele, o componente não será exibido;
  2. O componente possui uma visual mais complexo do que os outros, o que às vezes confunde o usuário;

Pesando as desvantagens e as vantagens, decidimos optar pelo Recaptcha, que se mostrou com a melhor relação entre os dois aspectos. Vamos ao que interessa: como colocar na aplicação.

A Solução

  1. Cadastre-se no site do Recaptcha para receber as chaves pública e privada que serão utilizadas pelo componente. O Google obrigado o uso de um domínio para o emprego do captcha. O cadastro pode ser feito aqui;
  2. Coloque o jar do Recaptcha no classpath da sua aplicação. O download pode ser feito aqui;
  3. Em um componente h:outputText coloque o código HTML gerado dinamicamente pelo serviço da Google com o atributo escape=false. O value do componente deve apontar para um método do Managed Bean que gera o captcha, porque a cada requisição deve ser lançado um novo desafio;
  4. 
    
  5. Implemente o método getCodigoHtmlRecaptcha(), conforme abaixo;
  6. /**
     * Gera o código HTML gerado pelo componente da Google.
     *
     * @return String - código HTML dinâmico
     */
       public String getCodigoHtmlRecaptcha() {
          ReCaptcha c = ReCaptchaFactory.newReCaptcha("chave pública fornecida pela Google", "chave privada fornecida pela Google", false);
    
          return c.createRecaptchaHtml(null, null);
       }
    
  7. Faça agora a validação do texto na Action chamada pelo commandButton ou commandLink, conforme métodos abaixo:
  8. 
    public String processaImagem() {
       try {
          if (!validaTextoImagem()) {
             /**
    	  *  COLOQUE AQUI A LÓGICA PARA A RESPOSTA ESTAR EM BRANCO OU INVÁLIDA.
    	  */
            return null; // permanece na mesma tela
          }
       } catch (ValidacaoCaptchaException e) {
          /**
           *  COLOQUE AQUI A LÓGICA PARA O COMPONENTE NÃO TER SIDO EXIBIDO CORRETAMENTE.
           */
          e.printStackTrace();
          return null; // permanece na mesma tela
       }
    
       // COLOQUE AQUI A LÓGICA PARA A IMAGEM TER SIDO VALIDADA COM SUCESSO
    
       return "sucessoCaptcha"; // o texto foi validado corretamente
    }
    
    /**
     * Valida o texto da imagem digitado pelo usuário.
     *
     * @return boolean indicando se o texto foi validado ou não
     * @throws ValidacaoCaptchaException caso o componente não tenha sido exibido corretamente
     */
    private boolean validaTextoImagem() throws ValidacaoCaptchaException {
       HttpServletRequest req = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
       String enderecoRemoto = req.getRemoteAddr();
       ReCaptchaImpl reCaptcha = new ReCaptchaImpl();
       reCaptcha.setPrivateKey("chave privada fornecida pela Google");
    
       String textoCriptografado = req.getParameter("recaptcha_challenge_field");
       String resposta = req.getParameter("recaptcha_response_field");
    
       /**
        *  Testa se o campo desafio está nulo ou vazio, ou se o campo resposta veio nulo (vem String
        *  vazia se o usuário não preencheu) e lança exception.
        */
       if (textoCriptografado == null || textoCriptografado.equals("") || resposta == null) {
          throw new ValidacaoCaptchaException("Dados submetidos não recuperados. Talvez exista um problema na exibição do componente captcha.");
       }
    
       ReCaptchaResponse reCaptchaResponse = reCaptcha.checkAnswer(enderecoRemoto, textoCriptografado, resposta);
    
       if (resposta.isEmpty() || !reCaptchaResponse.isValid()) {
          return false; // resposta em branco ou inválida
       } else {
          return true; // texto válido
       }
    }
    
    

Pronto! Somente isso. Quero ressaltar, antes que perguntem nos comentários, que ValidacaoCaptchaException é uma simples checked exception que extende Exception.

Seu componente será exibido na página conforme imagem abaixo:

Recaptcha no JSF

Recaptcha no JSF

Obviamente que a solução proposta nesse artigo é a mais simples possível. O ideal é não colocar a lógica de geração do código HTML em um método get, como foi feito. Para facilitar a manutenção, a chave privada pode ser colocada no web.xml, já que ela é referenciada mais de uma vez no código. Outro detalhe é que o uso de um componente facelet ajudaria na reutilização do captcha em várias páginas e ajudaria na validação do texto informado no componente e na estruturação do código como um todo. Só que mostrarei essa abordagem, juntamente com as outras duas melhorias comentadas acima em um próximo post.

Modificando o Idioma e a Cor

O Recaptcha da Google permite que você escolha o idioma das mensagens que aparecem quando se coloca o mouse em cima dos botões do componente e da frase que pede para inserir o texto. Outro atributo que você pode modificar é o esquema de cores do componente. Os dois atributos podem ser modificados com o seguinte código javascript:

<script type="text/javascript">
var RecaptchaOptions = {
   theme : 'cor_escolhida', // as opções são 'red' (default), 'white', 'blackglass' e 'clean'
   lang : 'pt'
};
</script>

Caso você queira modificar apenas um dos atributos (o tema ou o idioma), coloque apenas a linha correspondente, sem a vírgula que separa as duas instruções. O resultado com o tema branco (white) e o idioma português pode ser visto abaixo:

Recaptcha com skin branco e idioma português

Recaptcha com skin branco e idioma português

Anúncios
  1. manolo
    23/02/2011 às 17:48

    Muito legal, outra alteranativa é usar o primfeaces

    http://www.primefaces.org/showcase/ui/captcha.jsf

    abraçow

  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: