CRUD JSF 2 – Parte 3: Segurança com Spring Security 3

Olá pessoal,

Nos últimos posts recebi alguns pedidos para incrementar o CRUD JSF 2 com uma política de segurança utilizando o Spring Security 3. Lembrando que até a Parte 2 o CRUD contava com a utilização do framework Hibernate para auxiliar na persistência e a biblioteca de componentes PrimeFaces.

O Spring Security 3 é um framework que tem como objetivo auxiliar na autenticação e autorização dos usuários das aplicações. É uma ferramenta simples de ser utilizada, porém na integração com JSF é necessário alguns cuidados que serão apresentados neste artigo.

Caso você queira conhecer mais sobre o Spring Security 3 e suas novidades, está nas bancas neste mês de Janeiro/2011 na Java Magazine um artigo meu sobre o tema, detalhando muito mais o uso do framework e ensinando a utilizar o OpenId para criar alternativas de login nas aplicações. Clique aqui para acessar a Java Magazine 87.

Ao final, a tela de login que desenvolveremos ficará da seguinte forma:

O que já fizemos?

É interessante que você tenha acompanhado as 2 partes iniciais sobre o CRUD JSF 2 para que não fique perdido. Caso não tenha acompanhado seguem abaixo os links:

Parte 1: CRUD JSF 2 + Hibernate

Parte 2: CRUD JSF 2 + Hibernate + PrimeFaces

Passos para integrar o Spring Security 3

Antes de começar vamos ter uma visão geral do que será necessário para utilizar o framework. Cada passo será explicado e detalhado em seguida.

  • Incluir Novas Bibliotecas

O funcionamento correto do Spring Security 3 na aplicação exige a inclusão de 3 bibliotecas:

Caso você prefira, poderá baixar todas essas bibliotecas junto ao projeto disponibilizado no final do tutorial.

  • Arquivos de Configuração

Depois de adicionar as bibliotecas nós devemos “avisar” para a aplicação que o Spring Security será utilizado, dessa forma, os filtros que irão garantir acesso apenas para usuários autenticados e autorizados poderão agir. Para “avisar” devemos complementar o arquivo de configuração da aplicação web.xml e deixá-lo assim:



<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <context-param>
        <param-name>javax.faces.PROJECT_STAGE</param-name>
        <param-value>Development</param-value>
    </context-param>
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.jsf</url-pattern>
    </servlet-mapping>
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>

    <context-param>
        <param-name>primefaces.skin</param-name>
        <param-value>none</param-value>
    </context-param>

    <!-- Início das configurações para o Spring Security 3 -->
    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <!-- Fim das configuração para utilizar o Spring Security 3 -->

</web-app>


Depois disso temos que criar o arquivo de configuração do Spring Security 3. Este arquivo é responsável por definir as regras de acesso para as páginas, define também os usuários com permissão e suas autorizações, filtros e tudo mais relacionado a segurança da aplicação. O arquivo se chamará applicationContext.xml e deverá ser criado na pasta WEB-INF, assim como o arquivo web.xml. Veja como o applicationContext.xml deve ser descrito:



<?xml version="1.0" encoding="UTF-8"?>
<b:beans xmlns="http://www.springframework.org/schema/security"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:b="http://www.springframework.org/schema/beans"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
                            http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/security
                            http://www.springframework.org/schema/security/spring-security-3.0.xsd">

    <http auto-config="true" use-expressions="true">
        <intercept-url pattern="/index.jsf" access="hasRole('ROLE_USER')"/>
        <form-login login-page="/login.jsf" authentication-failure-url="/login.jsf?erro=true"/>
    </http>
    
    <authentication-manager>
        <authentication-provider>
            <jdbc-user-service data-source-ref="dataSource"
               users-by-username-query="SELECT username, password, enable FROM usuario WHERE username=?"
               authorities-by-username-query="SELECT Usuario_username as username, autorizacoes_nome as authority FROM usuario_autorizacao WHERE Usuario_username=?"
            />
        </authentication-provider>
    </authentication-manager>

    <b:bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" >
        <b:property name="url" value="jdbc:mysql://localhost:3306/livraria" />
        <b:property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <b:property name="username" value="root" />
        <b:property name="password" value="123" />
    </b:bean>

</b:beans>


Vamos entender melhor estas configurações. A tag <http> é responsável por definir as configurações de segurança para as páginas da aplicação. O atributo auto-config com o valor “true” automatiza algumas tarefas de configuração como a autenticação HTTP básica e o logout, além disso, com o auto-config ativado um formulário padrão de login é gerado, porém, como definimos a tag <form-login> este formulário não será gerado e sim criado por nós mais a frente. O atributo use-expressions é uma novidade da versão 3 do Spring Security, ela permite a utilização da linguagem de expressão SpEL para auxiliar a definir regras de acesso.

Dentro da tag <http> podemos definir inteceptadores através da tag <intercept-url>. Estes interceptadores vão criar restrições para as páginas da aplicação. No nosso caso a página index.xhtml poderá ser acessada apenas por usuários com o papel ROLE_USER.

O atributo login-page da tag <form-login> define a página na qual o formulário de login será descrito. Já o atributo authentication-failure-url define a página direcionada caso ocorra algum erro durante a autenticação.

Em seguida temos a tag <authentication-manager>, responsável por definir provedores de autenticação que gerenciam usuários e suas autorizações na aplicação. No nosso CRUD os usuários e suas autorizações serão buscados no banco de dados (configurado através do <bean> com id “dataSource”). A tag <jdbc-user-service> descreve nos atributos users-by-username-query e authorities-by-username-query as consultas que deverão ser realizadas no banco de dados para encontrar os usuários e suas autorizações.

Estas são as configurações de segurança que permitirão a autentição e autorização de usuários com o apoio do Spring Security 3. Vamos conhecer agora as novas classes necessárias para o CRUD.

  • Novas Classes

As novas classes que o CRUD vai precisar pertencem a dois pacotes o Model e o Controller.

  • Pacote Model
    • Neste pacote criaremos 2 novas classes. Uma que representa o usuário, com um username, um password, uma lista de autorizações e uma variável booleana chamada enable que determina se o usuário está ativo ou não. E a outra que representa a autorização e possui apenas uma string que descreve o nome de uma autorização. A seguir podemos ver como essas classes devem ser implementadas:

package Model;

import java.io.Serializable;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToMany;

@Entity
public class Usuario implements Serializable {

    @Id
    private String username;
    private String password;
    @Column(name = "enable", columnDefinition = "BOOLEAN")
    private boolean enable;
    @OneToMany
    private List<Autorizacao> autorizacoes;

    public Usuario() {
    }

    //getters and setters

}

}

Perceba que cada usuário pode várias autorizações, por isso utilizamos a annotation @OneToMany do Hibernate. Dessa forma quando formos gerar automaticamente as tabelas do banco elas serão criadas de acordo com esta definição.


package Model;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Autorizacao implements Serializable {

    @Id
    private String nome;

    public Autorizacao() {
    }

    //getter and setter

}

Para criar as tabelas correspondentes no banco de dados, você pode executar o trecho de código abaixo:


try {
        AnnotationConfiguration ac = new AnnotationConfiguration();
        ac.addAnnotatedClass(Livro.class);
        ac.addAnnotatedClass(Autorizacao.class);
        ac.addAnnotatedClass(Usuario.class);
        sessionFactory = ac.configure().buildSessionFactory();
        SchemaExport se = new SchemaExport(ac);
        se.create(true, true);
    }catch (Throwable ex) {
        System.err.println("Initial SessionFactory creation failed." + ex);
        throw new ExceptionInInitializerError(ex);
     }

  • Pacote Controller
    • Neste pacote criaremos uma classe chamada UsuarioController, esta classe é um managed bean que irá guardar o usuário logado no sistema. Ela deverá ser escrita da seguinte forma:

package Controller;

import Model.Usuario;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;

@ManagedBean
@SessionScoped
public class UsuarioController implements Serializable {

    private Usuario usuario;

    public UsuarioController() {
        usuario = new Usuario();
        SecurityContext context = SecurityContextHolder.getContext();
        if (context instanceof SecurityContext){
            Authentication authentication = context.getAuthentication();
            if (authentication instanceof Authentication){
                usuario.setUsername(((User)authentication.getPrincipal()).getUsername());
            }
        }
    }

    public Usuario getUsuario() {
        return usuario;
    }

    public void setUsuario(Usuario usuario) {
        this.usuario = usuario;
    }
    
}

Este managed bean possui a anotação @SessionScoped, com isso ele será mantido durante toda a sessão da aplicação. O primeiro momento em que ele será chamado é ao acessar a index.xhtml após efetuar o login com sucesso. Podemos ver no seu construtor a lógica para obter o usuário que realizou o login, utilizando para isso duas classes do Spring Security 3: a SecurityContext e a Authentication.

Com o back-end preparado, vamos conhecer agora as mudanças nas páginas xhtml do nosso CRUD.

  • Páginas xhtml

Vamos precisar criar apenas uma página na qual o usuário fará o login. Seu nome será login.xhtml e ela ficará dentro pasta web. Veja em seguida como a login.xhtml deverá ser escrita:


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:p="http://primefaces.prime.com.tr/ui">
    <h:head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
        <title>Bem vindo ao Gerenciador de Livros!</title>
        <link type="text/css" rel="stylesheet" href="dot-luv/skin.css"/>
    </h:head>
    <h:body style="background-image:url('http://pwes.rocklin.k12.ca.us/j0439526.jpg');background-position: 50% 0%;background-repeat: no-repeat">
        <p:dialog header="Login" visible="true" closable="false" draggable="false" resizable="false" width="420">
            <center>
                <h:outputText value="Usuário ou senha incorretos!" rendered="#{param.erro}" style="color: darkred"/>
            </center>
            <form action="j_spring_security_check" method="post">
                <h:panelGrid columns="2" cellpadding="5">
                    <h:outputLabel for="j_username" value="Username: *" /> 
                    <h:inputText id="j_username" required="true"/>
                    <h:outputLabel for="j_password" value="Password: * " />
                    <h:inputSecret id="j_password" required="true"/>
                    <h:commandButton value="Login"/>
                </h:panelGrid>
            </form>
        </p:dialog>
    </h:body>
</html>

Esta é uma página simples que utilizamos o component dialog do PrimeFaces para colocar o formulário de login. Note que não foi usada a tag <h:form> do JSF pois não realizaremos nenhuma lógica com managed beans para o login, deixando a responsabilidade da autenticação e autorização de usuários para o Spring Security. Por isso, utilizamos no atributo action do formulário o valor “j_spring_security_check”. Assim o filtro do Spring Security reconhecerá esse formulário como sendo de login e verificará o username e password dos inputs com valor j_username e j_password no atributo name.

Obs.: Como a tag <h:inputText> do JSF não possui o atributo name, era necessário saber como poderiamos definí-lo com o JSF, então descobri que o valor descrito no atributo id é utilizado para o atributo name quando as tags JSF forem convertidas para HTML, bastando assim utilizar j_username e j_password no id das tags.

Devemos prestar atenção também na tag <h:outputText> dentro da tag <center>. Ela possui o atributo rendered com valor “#{param.erro}” que nos diz: a tag será exibida quando for passado como parametro na url o atributo erro com valor true. Nós configuramos o arquivo de segurança para que isso aconteça durante as falhas de autenticação. O dialog de login ficará da seguinte forma quando essa tag estiver visível:

Nosso CRUD já está pronto para que os usuários efetuam login através do Spring Security, vamos apenas adicionar na página index.xhtml um link para o  logoff e vamos exibir uma mensagem de Boas vindas com o username do usuário logado. A tela ficará da seguinte forma:

Os códigos da index.xhtml atualizados ficaram assim:


<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:p="http://primefaces.prime.com.tr/ui">
    <h:head>
        <title>Gerenciador de Livros</title>
        <link type="text/css" rel="stylesheet" href="dot-luv/skin.css"/>
    </h:head>
    <h:body>
        <p:layout fullPage="true">
            <p:layoutUnit position="left" width="200" header="Atividades" resizable="true" closable="true" collapsible="true">
                <h:form prependId="false">
                    <p:commandLink value="Novo Livro" actionListener="#{livroController.prepararAdicionarLivro}" update="infosLivro" oncomplete="dialogGerLivro.show()"/>
                </h:form>
                <h:outputLink value="#{facesContext.externalContext.requestContextPath}/j_spring_security_logout">
                    <h:outputText value="Sair"/>
                </h:outputLink>
            </p:layoutUnit>
            <p:layoutUnit position="center">
                <h1>Gerenciador de Livros</h1><br/>
                <h:outputText value="Bem vindo #{usuarioController.usuario.username}, seus livros são:"/>
                <br/><br/>
                <h:form prependId="false">
                    <p:dataTable id="tabela" var="livro" value="#{livroController.listarLivros}">
                        <p:column>
                            <f:facet name="header">
                                <h:outputText value="Título"/>
                            </f:facet>
                            <h:outputText value="#{livro.titulo}" />
                        </p:column>
                        <p:column>
                            <f:facet name="header">
                                <h:outputText value="Autor"/>
                            </f:facet>
                            <h:outputText value="#{livro.autor}"/>
                        </p:column>
                        <p:column>
                            <f:facet name="header">
                                <h:outputText value="Páginas"/>
                            </f:facet>
                            <h:outputText value="#{livro.paginas}"/>
                        </p:column>
                        <p:column>
                            <f:facet name="header">
                                <h:outputText value="Editora"/>
                            </f:facet>
                            <h:outputText value="#{livro.editora}"/>
                        </p:column>
                        <p:column>
                            <f:facet name="header">
                                <h:outputText value="Isbn"/>
                            </f:facet>
                            <h:outputText value="#{livro.isbn}"/>
                        </p:column>
                        <p:column>
                            <f:facet name="header">
                                <h:outputText value="Avaliação"/>
                            </f:facet>
                            <h:outputText value="#{livro.avaliacao}"/>
                        </p:column>
                        <p:column>
                            <f:facet name="header">
                                <h:outputText value="Alterar"/>
                            </f:facet>
                            <p:commandButton actionListener="#{livroController.prepararAlterarLivro}" value="Alterar" update="infosLivro" oncomplete="dialogGerLivro.show()"/>
                        </p:column>
                        <p:column>
                            <f:facet name="header">
                                <h:outputText value="Excluir"/>
                            </f:facet>
                            <h:commandLink action="#{livroController.excluirLivro}" value="Excluir"/>
                        </p:column>
                    </p:dataTable>
                </h:form>
            </p:layoutUnit>
        </p:layout>

        <p:dialog header="Gerencia de Livro" widgetVar="dialogGerLivro"  resizable="false" modal="true" showEffect="slide" width="500">
            <h:form prependId="false">
                <h:panelGrid id="infosLivro" columns="2" style="margin-bottom:10px">

                    <h:outputLabel for="titulo" value="Título:" />
                    <h:inputText id="titulo" value="#{livroController.livro.titulo}"/>

                    <h:outputLabel for="autor" value="Autor:" />
                    <h:inputText id="autor" value="#{livroController.livro.autor}"/>

                    <h:outputLabel for="paginas" value="Páginas:" />
                    <h:inputText id="paginas" value="#{livroController.livro.paginas}"/>

                    <h:outputLabel for="editora" value="Editora:" />
                    <h:inputText id="editora" value="#{livroController.livro.editora}"/>

                    <h:outputLabel for="isbn" value="ISBN:" />
                    <h:inputText id="isbn" value="#{livroController.livro.isbn}"/>

                    <h:outputLabel for="avaliacao" value="Avaliação:" />
                    <h:selectOneMenu id="avaliacao" value="#{livroController.livro.avaliacao}">
                        <f:selectItem itemLabel="1" itemValue="1"/>
                        <f:selectItem itemLabel="2" itemValue="2"/>
                        <f:selectItem itemLabel="3" itemValue="3"/>
                        <f:selectItem itemLabel="4" itemValue="4"/>
                        <f:selectItem itemLabel="5" itemValue="5"/>
                    </h:selectOneMenu>

                    <p:commandButton update="tabela" oncomplete="dialogGerLivro.hide();" actionListener="#{livroController.adicionarLivro}" value="Inserir Livro"/>
                    <p:commandButton update="tabela" oncomplete="dialogGerLivro.hide();" actionListener="#{livroController.alterarLivro}" value="Alterar Livro"/>

                </h:panelGrid>
            </h:form>
        </p:dialog>
    </h:body>
</html>

O link que permite o logoff possui como valor “#{facesContext.externalContext.requestContextPath}/j_spring_security_logout”, ao clicar neste link o filtro do Spring Security reconhecerá que o usuário deseja realizar o logoff e se responsabilizará por esta tarefa.

A tag <h:outputText> com valor “Bem vindo #{usuarioController.usuario.username}, seus livros são:” vai buscar o username do usuário no managed bean UsuarioController.

Estas são as mudanças necessárias nas páginas do nosso CRUD para garantir sua segurança.

Agora basta inserir no banco de dados alguns usuários, a autorização ROLE_USER e ligar os usuários à autorização. Dessa forma, o CRUD estará pronto para funcionar.

Conclusão

Podemos observar que não é difícil integrar o Spring Security 3 com JSF 2 e este tutorial pode servir como base para o desenvolvedor aplicar uma política de segurança mais complexa com Spring Security nas suas aplicações com JSF 2.

O framework permite diversas outras maneiras de trabalhar a segurança da aplicação que não vimos aqui mas que você pode conhecer melhor nos livros recomendados.

Download

Projeto desenvolvido no Netbeans.

Clique aqui para fazer o download.

Livros Recomenados

  • Spring Security 3 – Peter Mularien

  • JSF 2 The Complete Reference – Ed Burns & Chris Schalk

Até a próxima pessoal!

126 comments for “CRUD JSF 2 – Parte 3: Segurança com Spring Security 3

  1. 25 de Janeiro de 2011 at 10:18

    If you could e-mail me with a few suggestions on just how you made your blog look this excellent, I would be grateful.

    • Vic Bormolini
      25 de Janeiro de 2011 at 18:10

      you are right, this is an excellent design and mainly, useful and professional contents. I’m really happy & grateful with this…
      I also suggest use http://www.weebly.com. It is easy and free.. you can see a site developed by myself. http://defineinformatica.weebly.com/

      good luck
      Vic

  2. Marcus
    7 de Fevereiro de 2011 at 16:52

    Minha aplicação acusa o erro

    HTTP Status 404 – /SECO/pages/j_spring_security_check

    Sabe dizer qual a causa?

    Obrigado.

    • 7 de Fevereiro de 2011 at 18:23

      Olá Marcus,

      Veja se 2 coisas estão corretas:

      1- No formulário da página login.xhtml veja se o valor do action é “j_spring_security_check”
      2- No xml de configuração applicationContext.xml veja se na tag o atributo login-page possui como valor a página onde está o formulário (se você seguiu o exemplo é a página “/login.xhtml”)

      Se não resolver me avise…

      Abraços,
      José Alexandre Macedo

      • 7 de Dezembro de 2012 at 15:51

        Ola alexandre estou com um dúvida , estou iniciando em jsf agora, minha dúvida é o seguinte, como eu faço um cadastro por exemplo de 1 autor ter vários livros ‘1:n’, ou um livro ter uma categoria? sem utilizar selectonemenu nos dois casos
        Vc tem algum exemplo assim?

  3. Vic Bormolini
    10 de Fevereiro de 2011 at 18:22

    olá Jose Alexandre… boa tarde.

    Estou preocupado, pois não ‘escuto’ mais se vc vai lançar alguma novidade boa… a última foi mesmo a parte 3 do CRUD? Tem alguma coisa no forno?

    Dúvida ou sugestão para um próximo tema… preciso imprimir o registro, tipo, criar um botão “Imprimir” ao lado do botão “Editar” e tbem preciso de um outro relatório, mostrando todos os registros de um determinado perído entre datas…. Tem idéia?

    obrigado e um abraço
    Vic

    • 11 de Fevereiro de 2011 at 16:04

      Olá Vic!
      Tudo jóia?!
      Estou te devendo umas respostas por email… já chegou a resolver algo?!
      Agradeço suas sugestões! Com certeza vou escrever mais posts sim! Ainda não defini o próximo tema ainda.. acho que não vou escrever sobre relatorios por que o Camilo Lopes fez isso a algumas semanas atrás… mas estou pensando em alguma coisa :)! Qualquer outra sugestão é bem vinda!
      Abraços,
      José Alexandre Macedo

      • Vic Bormolini
        22 de Fevereiro de 2011 at 7:41

        Olha, sem palavras pra te agradecer. Aqui está ótimo.. “meu” crud está ficando show. Claro, sempre encontro um probleminha aqui ou outro ali, mas… estudando e pesquisando se consegue sair do buraco.
        Sobre o tema de Relatório, acho muito legal tbem, pois seria legal ter uma opçao da lista onde o usuário possa visualizar e imprimir tal registro. Eu tive um experiência muito boa utlizando o Primefaces para exportar registros.. funcionou direitinho.

        um abraço
        Vic

  4. Vic Bormolini
    22 de Fevereiro de 2011 at 7:46

    Somando valores de livros.
    Qual seria sua sugestão em poder estar fazendo cálculos de valores no JSF. Pois inseri um campo para determinar o valor do livro. Logo abaixo tem mais dois campos que é o valor do desconto e o valor total. (preço do livro – valor do desconto em reais = preço do livro)
    Tentei usar um javascript mas não está dando certo, pois, por alguma razão se trava na tela de cadastro e não consegue voltar para a lista. Voce tem alguma dica ou exemplo disso?

    obrigado e um abraço
    Vic

    • 28 de Fevereiro de 2011 at 16:57

      Olá Vic,

      Acho que seria melhor você passar os calculos do managed bean para a view ao invés de fazer a soma nela…

      Abraços,
      José Alexandre

  5. Leandro
    28 de Fevereiro de 2011 at 14:55

    Muito bom… resolvi meu erro com seu artigo.

    o unico problema q ocorreu foi quando não preencho os campos login e senha ele me retorna :

    HTTP Status 500 – java.lang.IllegalArgumentException: The login argument is required

    claro que é pq o login e obrigatório mais como tratar com requerid de não estou usando h:form

    • 28 de Fevereiro de 2011 at 17:09

      Olá Leandro,

      Você poderia resolver isso com um pequeno código javascript tipo esse:

      function validar() {
      if (document.getElementById(‘j_username’) == “” || document.getElementById(‘j_password’) == “”){
      alert (“Complete o preenchimento do login!”);
      return false;
      }
      }

      e no form:
      < form ... onSubmit="return validar()">

      Obs.: não testei mas qualquer coisa você me fala!

      Abraços,
      José Alexandre.

  6. Vic Bormolini
    9 de Março de 2011 at 23:21

    Ola J.Alexandre. Alguma novidade? Já tem algum artigo saindo do forno? Precisamos ‘expandir’ essa biblioteca . . . . rsrs

    abraços
    Vic

    • 14 de Março de 2011 at 20:21

      E ai Vic!!

      Tudo jóia?!

      Estou preparando um artigo sim mas é pra revista! terá jsf 2 no meio acho q vai gostar!

      Abraços,
      José Alexandre

      • Vic Bormolini
        17 de Março de 2011 at 23:10

        qual? javamagazine? me deixe saber…..

        um abraço
        Vic

  7. Peres
    13 de Março de 2011 at 4:16

    Olá,

    Consegui criar a aplicação utilizando o eclipse. E foi gerado além da tabela livro as seguintes tabelas autorizacao, usuario e usuario_autorizacao.
    A minha dúvida é: Como inserir um usuário válido com esse tipo de tabelas.

    Por exemplo

    insert into usuario values(‘root’, true, 123)
    insert into autorizacao(‘ROLE_USER’)
    insert into usuario_autorizacao(‘root’, ‘ROLE_USER’)

    Tá certo dessa forma

    • 14 de Março de 2011 at 20:19

      Olá Peres,

      Tudo jóia?!

      Esta certo dessa forma sim… qualquer outra dúvida estou aí!

      Abraços,
      José Alexandre

      • 28 de Agosto de 2012 at 18:12

        PRECISSO CRIAR A CONEXÃO MANUAL NO MYSQL, SE POR FAVOR PUDER ME PASSAR A ESTRUTURA SQL

  8. Andre
    22 de Março de 2011 at 15:55

    Olá José,

    Muito bom o artigo e muito legal ter postado para download o projeto.

    Estou com dúvidas sobre Spring Security. Seguinte, estou fazendo um aplicativo que preciso fazer o controle de permissões de telas e além disso de certos recursos da tela. Exemplo: tenho uma tela de cadastro, o usuario tem permissao para ver a tela e cadastrar, não tem permissão para exluir e alterar. (essas opções não apareceriam)

    Encontrei algumas dicas sobre isso no site

    so que não funciona com xhtml, somente em jsp,o pq eu não sei, eu não consigo fazer o xhtml enxergar a biblioteca spring-security-taglibs.
    Mas como quero utilizar muitos componentes do primefaces, e ele tem problemas para desenvolvimento em jsp, fica dificil.

    Tens alguma dica de como fazer esses controles de permissões ? Pode ser por Spring ou de outros métodos como vi por PhaseListener (mais braçal).

    vlw, abraço.

    • 23 de Março de 2011 at 10:07

      Olá Andre,

      Eu sei que existe essa biblioteca de componentes http://code.google.com/p/spring-security-facelets-taglib/ mais não cheguei a usá-la… outra forma seria utilizar o Spring Web Flow para realizar a integração com JSF2 e usar a tag library que ele disponibiliza… essa segunda opção é um pouco mais complexa e talvez não compense caso só esteja integrando o spring security com o jsf2!

      Qualquer coisa estou aí!

      Abraços,
      José Alexandre

      • 7 de Dezembro de 2012 at 15:48

        Olá alexandre estou com uma dúvida inicio em jsf agora e o seguinte como eu faço um cadastro por exemplo de 1 autor ter vários livros, ou um livro ter uma categória sem usar selectonemenu….? vc tem algum exemplo assim?
        Obrigado

  9. Rodrigo
    29 de Março de 2011 at 16:28

    Qual as tabelas que devem ser criados, e os tipos???

    • 30 de Março de 2011 at 9:45

      Olá Rodrigo,

      O Hibernate pode criar as tabelas para você:

      AnnotationConfiguration ac = new AnnotationConfiguration();
      ac.addAnnotatedClass(Livro.class);
      ac.addAnnotatedClass(Autorizacao.class);
      ac.addAnnotatedClass(Usuario.class);
      sessionFactory = ac.configure().buildSessionFactory();
      SchemaExport se = new SchemaExport(ac);
      se.create(true, true);
      }catch (Throwable ex) {
      System.err.println(“Initial SessionFactory creation failed.” + ex);
      throw new ExceptionInInitializerError(ex);
      }

      Abraços,
      José Alexandre

  10. Sergio
    29 de Março de 2011 at 23:27

    O meu sistema ta validando atrasado pelo fato do jsf atualizar o link apos mandar uma ação quando esta naquela pagina, exemplo se estou na pagina de cliente.jsf, no link so vai ser atualizado apos eu sair dela.

  11. Tiago de Almeida
    5 de Abril de 2011 at 9:59

    Olá Alexandre,

    Parabéns pela iniciativa de divulgar o uso do Prime.

    Estou com o seguinte problema com o primefaces , quando acesso a aplicação via Firefox funciona todos os css e efeito de hover nos componetes como botoes e inputtext . So que o mesmo não acontece no IE 7/8.
    Essa configuração do prime no web.xml

    primefaces.THEME
    aristo

    Já passou por esse problema ? Qual foi a solução ?

    Abs.
    Tiago

    • 11 de Abril de 2011 at 11:17

      Olá Tiago,

      Tudo jóia?!

      Então.. já passei por isso sim.. e não fiquei procurando mto uma solução não… talvez seja possível alterar os css utilizados pelo prime mas não sei ate q ponto vale a pena… essa é uma das desvantagens dos componentes do jsf o resultado fica mto bom e não é necessário mexer mto com css e javascript porem em alguns momentos surgem limitações como essas…

      Abraços,
      José Alexandre

  12. hclcortez
    14 de Abril de 2011 at 17:35

    Muito bom post. Mas estou com um problema.. Já tinha minha aplicação feita usando JSF + PrimeFaces. Apenas adicionei o sistema de login com o spring. Quando o spring gera a tela de login (sem o form-login) funciona tranquilo. Mas quando coloco uma tela de login ele até me redireciona para a pagina de login, mas naõ me mostra nata. Parece-me que ele não mostra os componentes do PrimeFaces. e nem os estilos.

    • 14 de Abril de 2011 at 19:32

      Olá Hover,

      Fico feliz que tenha gostado do post. Não consegui ainda entender mto bem seu problema. Você usa o Spring também ou só o Spring Security?!
      Você poderia tentar explicar o problema de outra forma?!

      Abraços,
      José Alexandre Macedo

  13. Vicente
    28 de Abril de 2011 at 16:02

    Olá José, muito bom o post!
    Baixei o projeto, mas estou com problema na persistência, após inserir o usuário válido no banco.

    Por exemplo

    insert into usuario values(‘Vicente’, true, 123)
    insert into autorizacao(‘ROLE_USER’)
    insert into usuário_autorizacao(‘Vicente’, ‘ROLE_USER’)

    Na primeira vez faço o login funciona perfeitamente, mas ao sair e tentar logar novamente, não tenho mais a autorização. Olhei no BD percebi que não estão mais os dados referente a o usuário valido que tinha adicionado. Apenas as informações sobre o livro permanecem, mas mesmo assim quando adiciono novamente, novo usuário, faço login funciona, mas os dados referente ao livro que já estavam no banco são também apagados.

    Será que vc pode dar uma dica sobre o que pode está acarretando isto. Um abraço!

    • Neto
      27 de Maio de 2011 at 17:55

      Vicente, verifique se na configuração do arquivo hibernate.cfg.xml existe a linha: create caso esteja apague ou comente-a, pois essa linha recria as tabelas do banco…

  14. Felipe Lemos
    28 de Maio de 2011 at 10:09

    Amigo, mto bom o tutorial. Me tire uma dúvida, estou tentando recuperar outros dados do usuário da sessão, exemplo o nome do usuário e não consigo, vem null. Adicionei já o campo no bean e nada. Só consigo exibir o username do usuário, tentei recuperar via managed bean e nd tb. Se puder ajudar, agradeço.

    • 29 de Maio de 2011 at 15:28

      Olá Felipe,

      Você já atualizou as tabelas com essas novas informações no banco?

      Abraços,
      José Alexandre.

      • Felipe Lemos
        31 de Maio de 2011 at 15:07

        Sim, os campos q quero exibir já estão no banco. Não sei pq mas eu só consigo exibir o ‘Username’ do usuario, se tento exibir outros campos, vem em branco.

  15. Yian Zaratin
    1 de Junho de 2011 at 10:57

    Bom dia
    Desculpe a falta de conhecimento no assunto, tem como vc mandar o codigo sql para criar a tabela usuário para realizar a autenticação ….

    Obrigado

    • 1 de Junho de 2011 at 19:18

      Olá Yian,

      O Hibernate pode criar as tabelas para você:

      AnnotationConfiguration ac = new AnnotationConfiguration();
      ac.addAnnotatedClass(Livro.class);
      ac.addAnnotatedClass(Autorizacao.class);
      ac.addAnnotatedClass(Usuario.class);
      sessionFactory = ac.configure().buildSessionFactory();
      SchemaExport se = new SchemaExport(ac);
      se.create(true, true);
      }catch (Throwable ex) {
      System.err.println(“Initial SessionFactory creation failed.” + ex);
      throw new ExceptionInInitializerError(ex);
      }

      Abraços,
      José Alexandre

    • Vagner J Santos
      26 de Junho de 2011 at 17:39

      Boa tarde,

      Gostaria de saber se não é possivel você disponibilizar o codigo do banco, pois creio que muitos com eu, estão com dificudades com isso, caso alguma outro leitor tenha o codigo, peço a gentilela que me envie.

      Meu email segue abaixo;
      vjsantosuniban@gmail.com

      desde ja agradeço!

      Vagner

      • 27 de Junho de 2011 at 16:31

        Olá Vagner!
        Os códigos do banco de dados podem ser gerados através do hibernate a partir de uma classe que execute o seguinte trecho:

        try {
        AnnotationConfiguration ac = new AnnotationConfiguration();
        ac.addAnnotatedClass(Livro.class);
        ac.addAnnotatedClass(Autorizacao.class);
        ac.addAnnotatedClass(Usuario.class);
        sessionFactory = ac.configure().buildSessionFactory();
        SchemaExport se = new SchemaExport(ac);
        se.create(true, true);
        }catch (Throwable ex) {
        System.err.println(“Initial SessionFactory creation failed.” + ex);
        throw new ExceptionInInitializerError(ex);
        }

        Qualquer dúvida estou aí!

        Abraços,
        José Alexandre

  16. Vagner J Santos
    29 de Junho de 2011 at 9:51

    Bom dia,

    Estou usando o servidor php vertrigo como meu banco, ja executei o trecho que falou, porem não gera no banco, teria como você postar o codigo do banco, vejo que não sou o unico com esta dificuldade.

    Grato!

    • 1 de Julho de 2011 at 13:51

      Olá Vagner,

      O Dump do banco segue abaixo, provavelmente você vai ter q trocar essa aspa ` por ‘
      Qualquer coisa você me fala…
      Abraços

      CREATE DATABASE IF NOT EXISTS livraria;
      USE livraria;


      — Definition of table `autorizacao`

      DROP TABLE IF EXISTS `autorizacao`;
      CREATE TABLE `autorizacao` (
      `nome` varchar(255) NOT NULL,
      PRIMARY KEY (`nome`)
      ) ENGINE=InnoDB DEFAULT CHARSET=latin1;


      — Dumping data for table `autorizacao`

      /*!40000 ALTER TABLE `autorizacao` DISABLE KEYS */;
      INSERT INTO `autorizacao` (`nome`) VALUES
      (‘ROLE_USER’);
      /*!40000 ALTER TABLE `autorizacao` ENABLE KEYS */;


      — Definition of table `livro`

      DROP TABLE IF EXISTS `livro`;
      CREATE TABLE `livro` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT,
      `autor` varchar(255) DEFAULT NULL,
      `avaliacao` int(11) NOT NULL,
      `editora` varchar(255) DEFAULT NULL,
      `isbn` varchar(255) DEFAULT NULL,
      `paginas` int(11) NOT NULL,
      `titulo` varchar(255) DEFAULT NULL,
      PRIMARY KEY (`id`)
      ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;


      — Dumping data for table `livro`

      /*!40000 ALTER TABLE `livro` DISABLE KEYS */;
      INSERT INTO `livro` (`id`,`autor`,`avaliacao`,`editora`,`isbn`,`paginas`,`titulo`) VALUES
      (1,’jkhjkh’,3,’khkjh’,’897′,879,’jkhk’);
      /*!40000 ALTER TABLE `livro` ENABLE KEYS */;


      — Definition of table `usuario`

      DROP TABLE IF EXISTS `usuario`;
      CREATE TABLE `usuario` (
      `username` varchar(255) NOT NULL,
      `enable` tinyint(1) DEFAULT NULL,
      `password` varchar(255) DEFAULT NULL,
      PRIMARY KEY (`username`)
      ) ENGINE=InnoDB DEFAULT CHARSET=latin1;


      — Dumping data for table `usuario`

      /*!40000 ALTER TABLE `usuario` DISABLE KEYS */;
      INSERT INTO `usuario` (`username`,`enable`,`password`) VALUES
      (‘jam’,1,’123′);
      /*!40000 ALTER TABLE `usuario` ENABLE KEYS */;


      — Definition of table `usuario_autorizacao`

      DROP TABLE IF EXISTS `usuario_autorizacao`;
      CREATE TABLE `usuario_autorizacao` (
      `Usuario_username` varchar(255) NOT NULL,
      `autorizacoes_nome` varchar(255) NOT NULL,
      UNIQUE KEY `autorizacoes_nome` (`autorizacoes_nome`),
      KEY `FKD04AA31379DDB250` (`autorizacoes_nome`),
      KEY `FKD04AA3139FEF07F0` (`Usuario_username`),
      CONSTRAINT `FKD04AA31379DDB250` FOREIGN KEY (`autorizacoes_nome`) REFERENCES `autorizacao` (`nome`),
      CONSTRAINT `FKD04AA3139FEF07F0` FOREIGN KEY (`Usuario_username`) REFERENCES `usuario` (`username`)
      ) ENGINE=InnoDB DEFAULT CHARSET=latin1;


      — Dumping data for table `usuario_autorizacao`

      /*!40000 ALTER TABLE `usuario_autorizacao` DISABLE KEYS */;
      INSERT INTO `usuario_autorizacao` (`Usuario_username`,`autorizacoes_nome`) VALUES
      (‘jam’,’ROLE_USER’);

      • 1 de Julho de 2011 at 13:52

        Dava pra melhorar isso… mas como meu tempo ta bemm corrido e vc esta com pressa acho que isso já te ajuda! 🙂

      • Renan
        7 de Agosto de 2011 at 2:42

        Ta criando automatico na tabela usuario_autorizacao UNIQUE KEY `autorizacoes_nome` com isso nao to conseguindo inserir mais de um usuario com o mesmo role. Como faço pra isso nao gerar?

    • 1 de Outubro de 2012 at 14:35

      hola santos vos ya hiciste correr ese ejemplo con varias tablas no se si me lo podes pasar para que yo lo vuelva hacer por favor

  17. Fabricio
    30 de Junho de 2011 at 11:51

    Bom dia.

    Eu criei o banco, subi a aplicação no tomcat, populei o banco com o codigo abaixo
    package Utils;

    import Model.Autorizacao;
    import Model.Usuario;
    import java.sql.SQLException;
    import java.util.ArrayList;
    import java.util.List;
    import org.hibernate.Session;
    import org.hibernate.Transaction;
    import org.springframework.security.authentication.encoding.ShaPasswordEncoder;

    /*
    * To change this template, choose Tools | Templates
    * and open the template in the editor.
    */
    /**
    *
    * @author José Alexandre
    */
    public class HibernateTest {

    public static void main(String[] args) throws SQLException {

    Session session = HibernateUtil.getSessionFactory().openSession();
    Transaction t = session.beginTransaction();

    Autorizacao autorizacao = new Autorizacao();
    autorizacao.setNome(“ROLE_USER”);
    session.save(autorizacao);

    List autos = new ArrayList();
    autos.add(autorizacao);

    Usuario usuario = new Usuario();
    usuario.setEnable(true);
    usuario.setUsername(“fabricio”);
    usuario.setAutorizacoes(autos);
    usuario.setPassword(new ShaPasswordEncoder().encodePassword(“mudar123”, null));
    session.save(usuario);
    t.commit();

    session.close();

    }
    }

    mas não consegui logar no sistema, a encriptação é feita pelo ShaPasswordEncoder ou outro enconder ?

    Abraço

    Parabens pelo exemplo, muito bem detalhado.

  18. Fabricio
    30 de Junho de 2011 at 12:10

    opa bom dia novamente, resolvi o problema, esqueci de colocar o
    no do arquivo applicationContext.xml.

    Abraço

  19. Jaqueline
    4 de Julho de 2011 at 14:50

    OI, achei ótimo o seu post, entendi perfeitamente o que você fez!
    mas na hora de efetuar o login, eu não consigo logar :S
    tem como me ajudar?
    obrigada!

  20. Jaqueline
    4 de Julho de 2011 at 14:51

    Oii, achei ótimo o seu post, entendi perfeitamente o que você fez!
    mas na hora de efetuar o login, eu não consigo logar :S
    tem como me ajudar?
    obrigada!

    • Jaqueline
      4 de Julho de 2011 at 15:05

      The button/link/text component needs to have a Form in its ancestry. Please add .
      esqueci de comentar sobre o erro citado acima :S

    • 4 de Julho de 2011 at 15:59

      Olá Jaqueline,

      O que mais aparece no tomcat?
      O código que você utilizou não possui nenhuma diferença com relação ao que esta no site?

      Abraços,
      José Alexandre

  21. Silvio Paganini
    20 de Julho de 2011 at 22:59

    Parabéns José Alexandre, estou iniciando em programação web, mas já consegui evoluir bastante com seus tutoriais. Só não consegui identificar a mensagem que aparece na tela ao carregar a tela de login.
    The button/link/text component needs to have a Form in its ancestry. Please add .

    Sabe se foi algo que eu alterei?

    Obrigado.

    • 27 de Julho de 2011 at 14:57

      Olá Silvio,

      Pode ter sido algo que você alterou… o que você teria alterado?

      Abraços,
      José Alexandre

  22. Renan
    4 de Agosto de 2011 at 16:04

    Uma dúvida
    ele cria a tabela usuario e a tabela autorizacao
    e automaticamente ele cria a tabela usuario_autorizacao
    como eu faço pra inserir os registros automaticamente nessa tabela?

  23. Helcio
    11 de Agosto de 2011 at 21:47

    Parabéns pelo Artigo consegui implementar mas aparece o mesmo problema The button/link/text component needs to have a Form in its ancestry. Please add. Só alterei os nomes em inglês!

  24. Miguel
    24 de Agosto de 2011 at 1:09

    Muito bom!!!
    Baixei populei as tabelas…. funcionou corretamente!!!!

    • Varlue
      18 de Outubro de 2013 at 14:14

      Pessoal, alguem pode me ajudar? Não consigo fazer este exemplo de login com spring funcionar .. Grata!!

  25. Mario
    26 de Agosto de 2011 at 8:52

    INFO: SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase]

    Não consigo resolver este problema?

  26. Carlos
    26 de Agosto de 2011 at 14:21

    Opa, muito bom o artigo =D

    Deixa eu perguntar, se eu quiser depois que o usuário logar no banco fazer um update na tabela com a data do ultimo acesso (a data que ele logou)? Tem como?

    Dentro do applicationContext.xml

  27. Levy
    31 de Agosto de 2011 at 10:54

    Ola Alexandre.

    Parabéns pelo post.

    Estou com uma duvida.

    Tenho um usuario cliente e outro gerente. Algumas páginas do sistema sao reservadas somente para o gerente, logo na tag eu utilizo o access=”hasRole(‘ROLE_USER_GERENTE’)”. Minha duvida é: como eu coloco uma página em comum para o cliente e o gerente? Por exemplo, um index que pode ser acessado tanto pelo cliente quanto pelo gerente?

    • Sou Anônimo msm
      8 de Maio de 2017 at 9:22

      É isso ae cara

  28. Breno Lopes
    6 de Setembro de 2011 at 15:38

    Estou tendo problemas em adaptar o exemplo acima ao sistema que estou trabalhando, segue abaixo as adaptações:

    1º web.xml

    sigpub

    index.html
    index.htm
    index.jsp
    default.html
    default.htm
    default.jsp

    javax.faces.STATE_SAVING_METHOD
    server

    primefaces.THEME
    redmond

    Faces Servlet
    javax.faces.webapp.FacesServlet
    1

    Faces Servlet
    *.xhtml

    springSecurityFilterChain
    org.springframework.web.filter.DelegatingFilterProxy

    org.springframework.web.context.ContextLoaderListener

    springSecurityFilterChain
    /*

    2º applicationContext.xml






    3º classe Usuario

    // imports
    @Entity
    public class Usuario{

    @Id
    @GeneratedValue
    private Long id;
    @NotNull
    @NotEmpty
    private String login;
    @NotNull
    @NotEmpty
    private String senha;
    private boolean ativo;
    @OneToMany
    private List autorizacoes;
    //getters and setters
    }

    4º classe Autorizacao
    //imports
    @Entity
    public class Autorizacao{

    @Id
    private Long id;
    @NotNull
    @NotEmpty
    private String nome;
    //getters and setters
    }

    O seguinte erro está ocorrendo quando altero o xml e crio o applicationContext:

    DEPLOYMENTS IN ERROR:
    Deployment “jboss.web.deployment:war=/sigpub” is in error due to the following reason(s): org.jboss.deployers.spi.DeploymentException: URL file:/C:/Users/breno.lopes/eclipse-workspace/.metadata/.plugins/org.jboss.ide.eclipse.as.core/JBoss_6.0_Runtime_Server1315310838007/deploy/sigpub.war/ deployment failed

    at org.jboss.deployers.plugins.deployers.DeployersImpl.checkComplete(DeployersImpl.java:1370) [:2.2.0.GA]
    at org.jboss.deployers.plugins.deployers.DeployersImpl.checkComplete(DeployersImpl.java:1316) [:2.2.0.GA]
    at org.jboss.deployers.plugins.main.MainDeployerImpl.checkComplete(MainDeployerImpl.java:968) [:2.2.0.GA]
    at org.jboss.system.server.profileservice.deployers.MainDeployerPlugin.checkComplete(MainDeployerPlugin.java:82) [:6.0.0.Final]
    at org.jboss.profileservice.dependency.ProfileControllerContext$DelegateDeployer.checkComplete(ProfileControllerContext.java:138) [:0.2.2]
    at org.jboss.profileservice.deployment.hotdeploy.HDScanner$HDScanAction.deploy(HDScanner.java:246) [:0.2.2]
    at org.jboss.profileservice.deployment.hotdeploy.HDScanner$HDScanAction.complete(HDScanner.java:192) [:0.2.2]
    at org.jboss.profileservice.management.TwoPCActionWrapper.doComplete(TwoPCActionWrapper.java:57) [:0.2.2]
    at org.jboss.profileservice.management.actions.AbstractTwoPhaseModificationAction.complete(AbstractTwoPhaseModificationAction.java:74) [:0.2.2]
    at org.jboss.profileservice.management.actions.AbstractTwoPhaseModificationAction.prepare(AbstractTwoPhaseModificationAction.java:95) [:0.2.2]
    at org.jboss.profileservice.management.ModificationSession.prepare(ModificationSession.java:87) [:0.2.2]
    at org.jboss.profileservice.management.AbstractActionController.internalPerfom(AbstractActionController.java:234) [:0.2.2]
    at org.jboss.profileservice.management.AbstractActionController.performWrite(AbstractActionController.java:213) [:0.2.2]
    at org.jboss.profileservice.management.AbstractActionController.perform(AbstractActionController.java:150) [:0.2.2]
    at org.jboss.profileservice.management.AbstractActionController.perform(AbstractActionController.java:135) [:0.2.2]
    at org.jboss.profileservice.deployment.hotdeploy.HDScanner.scan(HDScanner.java:146) [:0.2.2]
    at org.jboss.profileservice.deployment.hotdeploy.HDScanner.run(HDScanner.java:90) [:0.2.2]
    at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source) [:1.6.0_26]
    at java.util.concurrent.FutureTask$Sync.innerRunAndReset(Unknown Source) [:1.6.0_26]
    at java.util.concurrent.FutureTask.runAndReset(Unknown Source) [:1.6.0_26]
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$101(Unknown Source) [:1.6.0_26]
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.runPeriodic(Unknown Source) [:1.6.0_26]
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source) [:1.6.0_26]
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source) [:1.6.0_26]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [:1.6.0_26]
    at java.lang.Thread.run(Unknown Source) [:1.6.0_26]

    alguma ideia do que seja, algo que eu esteja esquecendo? desde já agradeço a colaboração.

  29. Fábio Mattes
    26 de Setembro de 2011 at 21:00

    Olá José tudo bem, segui seu tutorial até e achei excelente mas nesta parte do spring securyt está retornando o seguinte erro:

    Erro durante a implementação: Exception while loading the app : java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleException: java.lang.RuntimeException: java.lang.NoClassDefFoundError: LModel/Usuario;

    estou usando o glassfish e o netbeans 7 com mysql 5, se puder me ajudar ficarei grato.

  30. Fábio Mattes
    26 de Setembro de 2011 at 22:26

    Opa José, consegui arrumar tudo aqui, refiz as class Usuario e Autorizacao e agora deu certo.

  31. Fábio Mattes
    27 de Setembro de 2011 at 12:21

    Você poderiam me dar uma dica de como eu poderia imprimir diretamente na lpt com jsf, tipo pegar o valor de alguns campos no primefaces e enviar para a impressora?

  32. Leandro
    27 de Setembro de 2011 at 22:04

    Estou com um problema no
    * No link para deslogar o usuário: “j_spring_security_logout”

    Ambiente: NetBeans 7.01 com o glassfish 3.1 rodando em Windows.

    Quando a pessoa clica para deslogar acontece isso no navegador web:

    type Status report
    message: “”
    descriptionThe requested resource () is not available.

    Detalhe:
    Tenho certeza de que de que o link está correto!
    O resto funciona normal, só o logout que não vai. Dá esse erro no console:

    Advertência: PWC4011: Unable to set request character encoding to UTF-8 from context /MeuProjeto, because request parameters have already been read, or ServletRequest.getReader() has already been called

    Alguma luz?

  33. Felipe Lemos
    28 de Setembro de 2011 at 11:30

    Parabéns José, eu me deparo com um probleminha há algum tempo: Se eu logar com um usuário e sem deslogar acessar a pagina de login, e logar com outro usuario, o spring loga com os dados do primeiro usuario e nao do segundo. Isso é um problema pois um usuario pode esquecer de deslogar e vim outro e logar e ter acesso aos dados do primeiro. Sabe alguma forma de resolver isso?

  34. mauro ramos
    30 de Setembro de 2011 at 23:12

    Olá Pode me ajudar esta retornando o erro abaixo, Obrigado.
    type Status report

    message /CrudLivros/login.jsf

    description The requested resource (/CrudLivros/login.jsf) is not available.

  35. Amauri Roberto mori
    3 de Novembro de 2011 at 14:16

    Olá, parabéns pela iniciativa.

    Consegui implementar tudo, mas surgiu uma dúvida.
    “Paginação”, fiz a padrão do prime, mas funciona até certo ponto(enquanto temos poucos registros na tabela), mas depois fica impraticavel.

    Poderia nos explicar como paginar no banco de dados sem perder as funcionalidades da paginação automatica do prime?

    Desde já agradeço a atenção

  36. Henrique Droog
    8 de Novembro de 2011 at 15:37

    Boa tarde J. Alexandre, primeiro gostaria de parabenizar pela série com JSF, PrimeFaces, Hibernate e Spring.

    Sou iniciante em Spring e gostaria de saber se é possível fazer as configurações do spring usando annotations.

    Valew obrigado.

  37. Felipe Gatti
    11 de Novembro de 2011 at 17:31

    José,

    Dei uma lida no seu post e adaptei pro meu problema aqui.. por enquanto perfeito!

    Agora estou com dúvidas sobre Spring Security. Estou fazendo um aplicativo que preciso fazer o controle de permissões de certos recursos da tela.

    Exemplo: Na index do seu projeto tem as opçoes “Novo livro”, “excluir” e “alterar”.. gostaria que essas só pudessem ser vistas por uma role de admin (nem ao menos apareceria a coluna “excluir” sem o botão ou com o botao inutilizado) entende?

    tem como eu fazer isso só com JSF e Spring security facilmente? Suguere algum link que tenha algo explicando isso? porque nao sei ao certo nem como pesquisar isso hehe..

    Desde já agradeço!

    Abraço,
    Felipe Gatti

  38. Daner
    22 de Novembro de 2011 at 10:19

    Parabéns pelo post. Muito completo e não deixa dúvidas…

  39. Marcelo
    4 de Dezembro de 2011 at 5:19

    Parabéns pelo post muito show,porém fiquei com uma dúvida…

    Quando faço login acesso uma página de cadastro, e realizo uma transação tudo ok… depois eu clico em sair… em seguida eu clico no voltar do navegador para a tela de cadastro digito os valores nos campos e mando submeter… o spring me redireciona para tela de login… até aqui tudo ok como esperado.. agora quando eu logo novamente o sistema executa a transação de quando eu estava offline e teitei submeter, percebi esse comportamento debugando pela fases.

  40. Felipe Gatti
    5 de Dezembro de 2011 at 12:29

    José,

    Dei uma lida no seu post e adaptei pro meu problema aqui.. por enquanto perfeito!

    Agora estou com dúvidas sobre Spring Security. Estou fazendo um aplicativo que preciso fazer o controle de permissões de certos recursos da tela.

    Exemplo: Na index do seu projeto tem as opçoes “Novo livro”, “excluir” e “alterar”.. gostaria que essas só pudessem ser vistas por uma role de admin (nem ao menos apareceria a coluna “excluir” sem o botão ou com o botao inutilizado) entende?

    tem como eu fazer isso só com JSF e Spring security facilmente? Suguere algum link que tenha algo explicando isso? porque nao sei ao certo nem como pesquisar isso hehe..

    Como dito no post acima, continuo com essas duvidas hehe..

    Andei procurando muito na net e o que axei foi que a integração do JSF com o Spring Security(SS)(taglibs) ainda não foi implementada.. axei algumas implementações disso, mas não oficiais, e não consegui fazer elas rodarem..

    Voce sabe mais sobre essas taglibs com JSF?
    Tem algum exemplo que rode?

    Desde já agradeço.

    Abraço,
    Felipe Gatti.

  41. Henrique Droog
    14 de Dezembro de 2011 at 17:54

    Boa tarde José Alexandre!!!

    Primeiro gostaria de agradecer pois este post me ajudou muito.
    Sou iniciante em java e também em spring e tenho uma dúvida. Eu preciso fazer um controle de sessão, vc tem algum material para indicar ou mesmo uma dica do procurar para fazer este controle?

    Desde já agradeço.

  42. Marcia
    15 de Dezembro de 2011 at 15:55

    Boa Tarde,

    Parabéns pelo tutorial muito didático.
    Mas mesmo assim estou com uma dificuldade.
    Baixei o seu fonte, instalei no NetBeans e quando executo ele abre a tela de login, mas não consigo me logar.
    Como alguém em um comentário anterior disse algo sobre o nome da Tabela com letra maiúscula, criei duas tabelas com o mesmo contúdo, uma como Usuario e outra como usuario, mas mesmo assim não consigo me logar. Não é gerado nenhuma mensagem de erro.

    Baixei também o fonte do 4shared p/eclipse e usando a mesma conexão de banco, funciona certinho.

    Mas queria usar o spring security.

    Será que alguém pode me ajudar?

    • 20 de Dezembro de 2011 at 14:44

      Olá Márcia,

      Chegou a criar as tabelas através do hibernate, dessa forma:

      try {
      AnnotationConfiguration ac = new AnnotationConfiguration();
      ac.addAnnotatedClass(Livro.class);
      ac.addAnnotatedClass(Autorizacao.class);
      ac.addAnnotatedClass(Usuario.class);
      sessionFactory = ac.configure().buildSessionFactory();
      SchemaExport se = new SchemaExport(ac);
      se.create(true, true);
      }catch (Throwable ex) {
      System.err.println(“Initial SessionFactory creation failed.” + ex);
      throw new ExceptionInInitializerError(ex);
      }

      Abraços,
      José Alexandre

  43. Michel orth
    18 de Dezembro de 2011 at 19:54

    olá muito bom seu tópico só que estou tendo uma dificuldade… fiz um sistema só falta essa parte de login mesmo…. minha estrutura da tabela é assim:

    idFuncionario, bairro, celular, cep, cidade, cpf, dataNascimento, email, enable, endereco, estado, fone, login, nome, nomeMae, nomePai, rg, senha, sexo

    ja inseri certinho um usuario mas ele ta dando usuario e senhas invalidas …. vou postar o applicationContext.xml que creio que seja aki o problema

    aqui esta certo?

    obrgado

    • Michel orth
      18 de Dezembro de 2011 at 19:56

      aki esta meu codigo do applicationContext.xml

      • Michel orth
        18 de Dezembro de 2011 at 19:56

        users-by-username-query=”SELECT login, senha, enable FROM Funcionario WHERE login=?”
        authorities-by-username-query=”SELECT Funcionario_idFuncionario as login, autorizacoes_nome as authority FROM funcionario_autorizacao WHERE Funcionario_login=?” />

  44. adanilson
    4 de Janeiro de 2012 at 9:12

    Boa tarde jamacedo estou com um problema ao fazer a parte de segurança

    da um erro ja pesquisar e n consegui nada,….

    ele da esse erro qdo ponho a user e password :

    org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
    INFO: Loading XML bean definitions from class path resource [org/springframework/jdbc/support/sql-error-codes.xml]

    org.springframework.jdbc.support.SQLErrorCodesFactory
    INFO: SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase]

  45. 2 de Fevereiro de 2012 at 20:04

    Olá JMacedo.

    Show de bola seu exemplo me ajudou muito. Integrado ao meu sistema 100%. Agora eu gostaria de capturar o nome do usuário e não apenas o login e sua senha para exibir na tela inicial. Pode me ajudar com isso.

    Obrigado.

  46. Volverinejr
    13 de Fevereiro de 2012 at 17:44

    O artigo está bem interessante, parabéns.
    poderia adicionar a segurança por método também o que você acha?
    dei uma olhada e vi o item @PreAuthorize(“hasRole(‘ROLE_SUPERVISOR’)”)
    mas não consegui utilizar, dá erro quando adiciono no meu applicationContext.xml, tem como dar uma ajuda.

  47. Weles
    26 de Fevereiro de 2012 at 18:31

    Parabéns pelo artigo! São artigos assim que fazem a comunidade crescer.
    Mas há algo que me deixou intrigado. No applicationContext vc informa o banco database e td mais, porém vc acaba utilizando o hibernate.cfg e repete as informações.
    O correto seria ter uma sessionaFactory e fazer a injeção correto? Ou existe algo no jsf que impessa isto?

    Obrigado pela atenção!

    Um abraço!

  48. João Guedes de Brito
    27 de Fevereiro de 2012 at 9:38

    Parabéns pelo post. Porém não consegui entender como são criados as tabelas no banco de dados. Você colocou para criar as tabelas no banco de dados execute o seguinte codigo:

    try {
    AnnotationConfiguration ac = new AnnotationConfiguration();
    ac.addAnnotatedClass(Livro.class);
    ac.addAnnotatedClass(Autorizacao.class);
    ac.addAnnotatedClass(Usuario.class);
    sessionFactory = ac.configure().buildSessionFactory();
    SchemaExport se = new SchemaExport(ac);
    se.create(true, true);
    }catch (Throwable ex) {
    System.err.println(“Initial SessionFactory creation failed.” + ex);
    throw new ExceptionInInitializerError(ex);
    }

    Em que Classe eu coloco o mesmo? Crio um novo método?

    No aguardo…E desde já agradeço…

  49. Felipe
    14 de Março de 2012 at 15:38

    Muito bom este post ensinando a validação de login.

    Estou com um problema, fiz tudo conforme descrito aqui, só que quando coloco usuario e senha na tela de login, ele nao loga e nem da msg de erro, ele simplesmente volta a ficar com os campos em branco e no tomcat aparece:
    MonitorFilter::WARNING: the monitor filter must be the first filter in the chain.
    O que estou fazendo de errado?

    Abraços

    • 26 de Março de 2012 at 14:12

      I have the same problem, I dont really know how this affect my deployment, but MonitorFilter::WARNING: the monitor filter must be the first filter in the chain appears many times on my netbeans console.

  50. 1 de Abril de 2012 at 19:41

    Olá, consegui fazer tudo funcionar perfeitamente. Eu tenho na minha página inicial dois panel group com as 2 situações:

    panel1 – será renderizado (mostrado) caso o usuário esteja deslogado
    panel2 – será renderizado (mostrado) caso o usuário esteja logado

    o painel 2 eu consegui fazer usando isso:

    eu tentei fazer o painel1 de várias formas… usando ! or not empty, várias maneiras e não consegui…

    Alguém teria uma idéia de como fazer?

  51. Jonathan
    11 de Abril de 2012 at 15:32

    Como faço pra configurar o hibernate pra construir as tabelas automaticamente?
    inseri o trecho no xml
    update

    mas não funcionou…

    abraços

    • Jonathan
      11 de Abril de 2012 at 15:33

      property name=”hibernate.hbm2ddl.auto” update

  52. Jorge Bavaresco
    9 de Maio de 2012 at 11:23

    Olá!
    Estou tentanto usar @PreAuthorize(“hasRole(‘MEU_ROLE_3’)”) nos meus métodos mas não faz a segurança. Se eu uso para fazer a segurança funciona. Mas preciso deixar os métodos seguros. Já adicionei isso no arquivo de configuração do spring mas também não vai. Se puder dar uma luz agradeço!

  53. Guilherme
    9 de Maio de 2012 at 20:52

    Minha aplicação dá o erro

    HTTP Status 404 – http://localhost:8080/Clientes/faces/views/j_spring_security_check

    Sabe dizer qual a causa?

    Obrigado.

    • Gabriel
      23 de Maio de 2012 at 12:40

      Resolvi no meu colocando o nome do projeto antes da chamada do j_spring_security_logout no link de Sair, no meu caso meu projeto é chamado de Projeto1.

  54. Gabriel
    23 de Maio de 2012 at 12:43

    h:outputLink value=”#{facesContext.externalContext.requestContextPath}Projeto1/j_spring_security_logout”>

    </h:outputLink

  55. Phill
    16 de Junho de 2012 at 22:15

    Kra …

    Qdo tento logar ele me redireciona para tela de login sempre …

  56. Phill
    16 de Junho de 2012 at 22:20

    O Complicado é que não aparece nenhum erro, apenas redireciona para tela de login sempre!

  57. Phill
    17 de Junho de 2012 at 11:26

    Consegui verificar o log …

    Your login attempt was not successful, try again.

    Reason: PreparedStatementCallback; SQL [SELECT login,senha FROM login WHERE login=?]; Column Index out of range, 3 > 2. ; nested exception is java.sql.SQLException: Column Index out of range, 3 > 2.

    Saberia o que pode ser esse erro ?

  58. patricia
    27 de Julho de 2012 at 11:24

    na telea de login da mensagem a Form in its ancestry. Please add . como resolver?

  59. 13 de Agosto de 2012 at 13:11

    Olá José!
    Gostaria de saber se ao invés de reconfigurar o bean id datasource para efetuar uma conexão ao banco, se é possível utilizar o datasource já configurado no Jboss AS 7.
    Obrigado

  60. 18 de Novembro de 2012 at 23:23

    Olá!
    Primeiro, muito bom tutorial!
    Agora uma dúvida: porque não funciona quando eu uso p:commandButton ao invés de h:commandButton, ou seja, o botão do primefaces não funciona.
    Você sabe o motivo?
    Outra coisa, se minha pasta não está na raíz, por exemplo, se eu tenho /public/login.xhtml, quando clico no botão, o spring tenta entrar em /public/j_spring_security_check e daí ele não funciona, tem solução?
    Abraços!

  61. Roni
    2 de Fevereiro de 2013 at 17:41

    Olá Parabéns pelo tutorial !! Fiz o tutorial mas quando realizo login está dando o erro 404 ele faz a autenticacao certinho mas nao abre o index.xhtml. O que pode ser?

  62. Robson
    16 de Fevereiro de 2013 at 18:23

    Olá boa tarde.

    Prezado seu artigo ajudou muito mais, como outros comentários eu tenho a necessidade de mostrar o nome do usuário na pagina e não o login do usuário, minha tabela usuário criada na minha aplicação onde estou estudando java tem campos diferentes, apesar disto esta autenticando normalmente… mais tenho campos de ide, login, senha, nome etc… gostaria de ter a funcionalidade de mostrar o nome do usuário.

    public class Usuario implements Serializable, UserDetails

  63. Tony
    25 de Março de 2013 at 15:07

    To tentando rodar meu projeto aqui no Eclipse e ta dando esse erro:
    HTTP Status 404 – /j_spring_security_check not found

    alguém pode me ajudar?

  64. Augusto
    16 de Abril de 2013 at 15:29

    Parabéns pela post, ficou muito claro e bem explicado.

  65. Augusto
    23 de Abril de 2013 at 10:47

    Só estou com um problema aqui.
    No meu caso não posso colocar o meu contexto do Spring dentro do WEB-INF pois minha aplicação está dividida em duas, e a primeira delas (não o projeto web) utiliza o contexto para levantar os serviços. Sugere algo nesse caso?
    Eu pensei em criar um XML exclusivo para trabalhar com security no Spring.

    Fico no aguardo amigo.

  66. 21 de Junho de 2013 at 13:12

    Olá Macedo,
    gostei muito do post, mas as tabelas do banco de dados você podia deixá-la disponível para download. Estou tentando implementar segurança em programa de teste. As tabelas de permissões de acesso ao sistema usuario e usuario_autorizacao

  67. Joao Moraes
    18 de Julho de 2013 at 14:11

    Parabéns pelo post, ficou muito legal e claro!
    Fiz o projeto mas quando rodo dá a seguinte mensagm:
    SEVERE: Exception while loading the app : java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleException: java.lang.IllegalArgumentException: java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener

    voc poderia me dar uma dica?

  68. 24 de Julho de 2013 at 9:46

    O que é bom merece ser reconhecido, o tutorial é simplesmente muito bom, simples, claro e objetivo e ainda muito didático. Parabéns José Alexandre!

  69. 6 de Agosto de 2013 at 2:40

    Parabéns! Seu artigo está muito bom. Foi muito útil para mim.

  70. Multiple Uses
    15 de Agosto de 2013 at 12:20

    Thanks a lot, man!!! This is really helpfull!!!

  71. Varlue
    18 de Outubro de 2013 at 14:26

    Pessoal, alguem pode me ajudar com o funcionamento deste post? Por algum motivo o login não funciona! Eu criei as tabelas através o scrip e inseri um usuário, mas este não se loga .. Grata!

  72. ely
    21 de Janeiro de 2014 at 21:15

    podes m dizer a cerca deste erro C:\app\P2012-09\P2012-09-war\nbproject\build-impl.xml:1087

  73. Helton Carlos
    10 de Março de 2014 at 10:50

    Muito bom post, só que to com uma séria duvida em fazer algo um pouco mais dinamico. Onde um usuario possa definir o que determinados grupos possam estar acessando. Se alguém pudesse me dar um help nisso agradeceria muito.

  74. 21 de Maio de 2014 at 9:49

    Segui o tutorial e achei muito bem explicado, ao executar minha aplicação e a as tabelas criadas corretamente (“autorizacao”, “usuario” e “usuario_autorizacao”)
    O problema está quando eu tento adicionar manualmente 2 autorizações (ROLE_USER e ROLE_ADMIN) e em seguida adicionar 2 usuários e fazer o relacionamento deles na tabela “usuario_autorizacao”, sempre dá duplicidade, não permite a entrada de 2 roles iguais para usuários diferentes na tabela de relacionamento:

    CREATE TABLE `autorizacao` (
    `nome` varchar(60) NOT NULL,
    PRIMARY KEY (`nome`)
    )

    CREATE TABLE `usuario` (
    `username` varchar(20) NOT NULL,
    `enable` tinyint(1) DEFAULT NULL,
    `password` varchar(20) DEFAULT NULL,
    PRIMARY KEY (`username`)
    )

    CREATE TABLE `usuario_autorizacao` (
    `usuario_username` varchar(20) NOT NULL,
    `autorizacoes_nome` varchar(60) NOT NULL,
    UNIQUE KEY `autorizacoes_nome` (`autorizacoes_nome`),
    KEY `FK222D335355E195CA` (`autorizacoes_nome`),
    KEY `FK222D3353F713B86A` (`usuario_username`),
    CONSTRAINT `FK222D3353F713B86A` FOREIGN KEY (`usuario_username`) REFERENCES `usuario` (`username`),
    CONSTRAINT `FK222D335355E195CA` FOREIGN KEY (`autorizacoes_nome`) REFERENCES `autorizacao` (`nome`)
    )

    Não tou conseguindo ajustar o mapeamento da entidade para resolver o problema. Alguém pode me dar uma ajuda?

  75. 26 de Junho de 2014 at 14:14

    Tem como fazer o sistema entrar em determinada tela de acordo com a roler ?

    • Dayan Costa
      27 de Novembro de 2014 at 9:50

      Não sei se já conseguiu fazer, mas procura sobre AuthenticationSuccessHandler essa interface tem um método que você implementa isso.

  76. Matheus
    7 de Julho de 2014 at 14:38

    Boa tarde Jamacedo, consegui fazer o seu exemplo funcionar, preciso adicionar mais papéis na aplicação, por exemplo, um administrador, como ficaria o aplicationContext nesse caso?

    Obrigado!

  77. Luis Borges
    14 de Outubro de 2014 at 18:05

    Boa noite Jamacedo, muito bom post porém tenho uma dúvida e no caso de não deixar o mesmo usuário logar mais de uma vez é possível fazer isso com o spring?

  78. Pablo Lopes
    2 de Maio de 2015 at 19:22

    Boa noite, segui o passo a passo, porém, não consigo fazer a autenticação… sempre aponta ERRO para TRUE… alguma dica?… e por sinal, tens um excelente site e material, parabéns.

  79. Luan Pinheiro
    19 de Maio de 2015 at 21:04

    Olá Alexandre, parabéns pelo seu excelente trabalho, admirador. Estou preso no mesmo problema do “Pablo Lopes” não consigo fazer a autenticação, sempre dá usuario e senha incorretos, acredito que a conexão com o banco de dados está ok, pode dar uma força? estou precisando muito.
    E novamente ótimo trabalho.

  80. 22 de Setembro de 2015 at 19:16

    Parabéns Alexandre, ficou sensacional cara, me ajudou pra caramba…sucessos !!!

  81. Glenio Montovani
    13 de Fevereiro de 2017 at 16:08

    O Post já é bem antigo, mas mesmo assim, parabéns José Alexandre pelo post, muito bom. Existem poucas em português que realmente sejam útil como esta que fez.

    Todavia, fiquei com uma duvida. Você criou a view(login.xhtml) e o controller (UsuarioController), mas na view não existem nenhuma chamada a nenhum metodo ou atributo do bean somente a configuração do Spring Security foi informada na view.

    1 – Como que ele irá entrar no construtor do Bean(controller)?
    2 – Somente pelo ciclo de vida normal ocorrido no JSF?
    3 – Se sim, caso algum infeliz faça a declaração em outros beans do método construtor o mesmo que fez no UsuarioController irá ocorre o que?

    Obrigado e desculpa a pergunta depois de tanto tempo do posts, mas isto e bem recorrente ainda.

    Abraços.

  82. Maycon
    18 de Maio de 2017 at 22:28

    Olá primeiramente parabéns pelo conteudo do seu blog, estou utilizando muito como base de estudo! Tenha uma dúvida neste seu projeto que não consegui alterar! É possivel colocar uma barra de pesquisa dos livro! Ai digito um nome e ele pesquisa os livros por parte deste nome!! Tentei e não consegui

Responder a Fabricio Cancelar resposta