quinta-feira, 19 de setembro de 2013

Configurando o Spring (III)

Este post faz parte de uma série sobre Spring, JPA e JSF. Caso algum assunto abordado aqui não esteja claro, consulte este link: Spring + JPA.

A utilização do Spring Security é bastante tranquila. Já uso em vários projetos e posso autenticar tanto por meio de um banco de dados, quanto por meio de uma base LDAP.

Vou mostrar com mais detalhes a autenticação por meio de um banco de dados. Vamos assumir que as tabelas com os usuários e as regras de acesso estão no mesmo banco de dados que será utilizado pelo sistema, e referenciado pelo identificador "fonteDeDados" que já apareceu em vários arquivos dos outros posts.

O arquivo security-config.xml é o último arquivo de configuração do Spring que vamos abordar, veja o código abaixo:

<?xml version="1.0" encoding="ISO-8859-1"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
             xmlns:beans="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:context="http://www.springframework.org/schema/context"
             xsi:schemaLocation="http://www.springframework.org/schema/beans 
             http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
             http://www.springframework.org/schema/security 
             http://www.springframework.org/schema/security/spring-security-3.1.xsd
             http://www.springframework.org/schema/context 
             http://www.springframework.org/schema/context/spring-context-3.1.xsd">
    <http use-expressions="true">
        <intercept-url pattern="/web/index.xhtml" access="isAuthenticated()" />
        <intercept-url pattern="/web/resources/**" access="permitAll" />
        <intercept-url pattern="/web/acessoNegado.xhtml" access="permitAll" />
        <intercept-url pattern="/web/login.xhtml" access="permitAll" />
        <intercept-url pattern="/web/ajaxDialog.xhtml" access="permitAll" />
        <intercept-url pattern="/web/resources/imagens/ajaxloading.gif" access="permitAll" />
        <intercept-url pattern="/web/menu.xhtml" access="isAuthenticated()" />
        <access-denied-handler error-page="/web/acessoNegado.xhtml" />
        <form-login login-page="/web/login.xhtml"
                    authentication-failure-url="/web/login.xhtml?login_error=1"/>
        <logout logout-success-url="/web/index.xhtml" />
    </http> 

    
    <authentication-manager>  
        <authentication-provider>  
            <!--password-encoder hash="md5"/-->  
            <jdbc-user-service data-source-ref="fonteDeDados"/>  
        </authentication-provider>  
    </authentication-manager>     
    
</beans:beans>

O código mais relevante do arquivo é o trecho entre as linhas 26 e 31. Percebemos aqui a presença do identificador "fonteDeDados", e depois da configuração do banco de dados que será utilizado pelo sistema, criamos neste mesmo banco as tabelas para os usuários e regras de autorização.

Caso seja necessária a utilização de criptografia, podemos descomentar a linha 28, mas as senhas deverão ser armazenadas já criptografadas no banco de dados. Para o exemplo, vamos armazenar as senhas em claro.

O trecho entre as linhas 20 e 23 determina quais os arquivos responsáveis pelo controle da autenticação. Podemos perceber claramente que devem ser criados os arquivos acessoNegado.xhtml e login.xhtml.

As linhas iniciadas por "intercept-url" determinam como vai ser autorizado o acesso a uma página ou a uma pasta. Podemos perceber que algumas páginas estão autorizadas se  for satisfeita a condição isAuthenticated(), e outras podem ser acessadas mesmo sem autenticação. Voltaremos a este assunto mais tarde, quando precisarmos restringir um conjunto de páginas administrativas, por exemplo. Caso o leitor precise de mais detalhes, a literatura sobre o Spring é muito ampla, um exemplo está neste link: http://docs.spring.io/spring-security/site/docs/3.0.x/reference/springsecurity-single.html

Uma grande vantagem da utilização do Spring para autenticação e autorização é que para deixar de utilizar um banco de dados e passar a utilizar uma base LDAP, precisamos modificar somente o trecho entre as linhas 26 e 31. Segue um exemplo:

    <ldap-server id="ldapServer" url="ldap://xxx.xxx.xxx.xxx:389" />
    <authentication-manager>        
        <!-- Trecho para autenticacao via ldap -->  
        <ldap-authentication-provider 
            user-search-base="ou=People,dc=meudominio,dc=com,dc=br" 
            group-search-base="ou=Groups,dc=meudominio,dc=com,dc=br">
        </ldap-authentication-provider>
    </authentication-manager>

Percebemos claramente a facilidade desta mudança. Apenas precisamos do IP do servidor LDAP e o restante da configuração continua o mesmo. Vamos encerrar mostrando o código dos arquivos acessoNegado.xhtml e login.xhtml:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- acessoNegado.xhtml -->
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html">
    <body>
        <div align="center">
            <h:panelGroup>
                <span style="color:red">Acesso negado.</span>
                < br/>
                < br/>
                <h:outputText value="Motivo: #{SPRING_SECURITY_LAST_EXCEPTION.message}" rendered="#{!SPRING_SECURITY_LAST_EXCEPTION.message==''}" />
            </h:panelGroup>

            <form id="login" method="post" action="#{facesContext.externalContext.request.contextPath}/web/index.xhtml">
                <h:commandButton type="submit" value="Voltar à página inicial"/>
            </form>
        </div>
    </body>
</html>


<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- login.xhtml -->
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:p="http://primefaces.org/ui">
    <body>
        <div align="center">
            <p:fieldset style="width:300px" >
                <h:panelGroup rendered="#{!empty param.login_error}">
                    <span style="color:red">Erro na autenticação.</span>
                    < br/>
                    < br/>
                    <h:outputText value="Confira o nome do usuário e a senha." />
                </h:panelGroup>
                <h1><h:outputText value="Autenticação" style="text-decoration: underline" /></h1>
                <form id="login" method="post" action="${request.contextPath}/j_spring_security_check">
                    <h:panelGrid columns="2">
                        <h:outputText value="Usuário: " />
                        <p:inputText id="j_username" />
                        <h:outputText value="Senha: " />
                        <p:password id="j_password" />
                    </h:panelGrid>
                    < br/>
                    <p:commandButton onclick="submit()" type="submit" value="Autenticar" global="false" />
                    <script>
                        document.getElementById("login").j_username.value = "#{SPRING_SECURITY_LAST_USERNAME}";
                    </script>
                </form>
            </p:fieldset>
        </div>
    </body>
</html>

Não há muito o que comentar quanto aos arquivos acima. Apenas as linhas 17, 20 e 22 do login.xhtml, que contêm identificadores que são esperados pelas classes de autenticação, e não devem ser modificados.

Uma última consideração quanto ao método de autenticação: se o login falhar, o arquivo login.xhtml é chamado novamente, com um parâmetro para indicar que houve erro (authentication-failure-url="/web/login.xhtml?login_error=1").

Para criar os usuários e as regras no banco de dados, podemos criar as tabelas com o sql a seguir:

    create table users(  
          username varchar(50) not null primary key,  
          password varchar(50) not null,  
          enabled boolean not null);  
      
    create table authorities (  
          username varchar(50) not null,  
          authority varchar(50) not null,  
          constraint fk_authorities_users foreign key(username) references users(username));  
          create unique index ix_auth_username on authorities (username,authority);  

Em seguida, basta inserir um usuário, senha, colocar verdadeiro no campo enabled e inserir uma regra, por exemplo, "admin".

No próximo post, a configuração da fonte de dados e do Jboss.

Nenhum comentário:

Postar um comentário