Faculdade de Tecnologia SENAC Goiás Projeto Integrador Programação com Frameworks Tutorial Financeiro WEB Spring Security Fernando Norberto Juliana Carvalho Thiago Junior Ester Xavier GTI V Matutino 2014
Passo 1 Configurando o servidor Apache Tomcat 7.0 1) Crie uma nova pasta com o nome de Servidores na unidade C:\ de seu computador. 2) Faça o Download do arquivo.zip : http://tomcat.apache.org/download-70.cgi Baixe o arquivo zip (pgp, md5), conforme a estrutura a seguir: Binary Distributions Core: zip (pgp, md5) tar.gz (pgp, md5) 32 bit Windows zip (pgp, md5) Para win 32. 64 bit Windows zip (pgp, md5) Para win 64. 64 bit Itanium Windows zip (pgp, md5) 32 bit/64 bit Windows Service Installer (pgp, md5) 3) Salve o arquivo zip (pgp, md5) dentro da pasta Servidores. 4) Abrir a IDE Eclipse (Versão Kleper JEE) e definir o espaço de trabalho na janela Workspace Launcher. Sendo esse espaço de trabalho o diretório onde os projetos serão armazenados. 5) Para criar um novo servidor, clique no link: (No servers are avaliable) Caso a guia Servers não esteja visível, siga o caminho a seguir :
Clicando em Other, abrirá uma nova Janela, conforme o exemplo: Selecione a opção Servers, Para criar a seguinte Estrutura:
6) Clique no link descrito acima, abrirá a janela a seguir: 7) Dentro da Pasta Apache, selecione Tomcat v7.0 Server e clique em next. 8) Na próxima janela clique no Botão Browse e selecione o servidor tomcat, que se encontra dentro da pasta Servidores, exemplo abaixo:
9) Clique em Installed JRes..., abrirá uma nova janela, clique em ADD, clicando em add abrirá uma nova janela, conforme o exemplo: 10) Selecione a opção Standard VM e clique em next, abrirá a janela JRE Definition, conforme a seguir:
11) Em JRE home clique no botão Directory e selecione a pasta onde o JDK (Kit de desenvolvimento java) está instalado, após clicar observe as alterações seguintes, conforme na imagem: 12) Clique em Finish, e depois selecione o arquivo que foi configurado e clique em ok, conforme a seguir:
13) Selecione o arquivo que foi configurado e clique em ok. 14) Na próxima janela, selecione o JDK que foi configurado, conforme o exemplo: Nesse exemplo foi configurado o JDK 1.8 15) Após selecionar o JDK, clique em next, depois em finish. 16) Verifique se o servidor foi criado na guia Servers, conforme o exemplo a seguir: 17) Conforme a imagem acima, clique com o botão direito em cima do Servidor Tomcat, depois disso clique em Start, para rodar o servidor, se tudo der certo ele irá ficar da seguinte forma:
18) Pronto, seu servidor foi configurado corretamente.
Passo 2 Criando o Projeto 1) Crie um Projeto usando a ferramenta Eclipse, com o nome: FinanceiroWeb. 2) O projeto ficará com a seguinte estrutura: Classes e Interfaces
Páginas
Passo 3 Configurando e instalando o Spring Security Descrição O Spring Security garante a autenticação e a autorização dos usuários, permitindo assim que somente quem realmente é cadastrado no sistema tenha acesso aos recursos restritos, com acesso somente ao conteúdo para o qual receba a permissão, no conteúdo restrito teremos 3 níveis de autorização: usuário normal, usuário administrador e usuário Vip. O que é o Spring? É um framework Java e de código fonte aberto que visa facilitar o desenvolvimento JavaEE. A funcionalidade básica do Spring é a instanciação de classes, realizando a injeção de dependências com base em definições em um arquivo de configuração XML criado pelo desenvolvedor, resultando baixo acoplamento entre as classes. O que o Spring faz por nós? Segurança de Pastas. Na pasta Admin foi criada a listagem de usuários, e apenas o usuário cadastrado com permissão de Administrador terá acesso a pasta. Os usuários cadastrados com permissão de apenas usuário, terão acesso apenas as pastas Publico, e Restrito. Concluindo então, ao separar adequadamente os recursos do sistema em pastas diferentes e ao configurar o Spring secutiry podemos garantir a segurança do acesso a determinadas pastas. Controle de Login Sempre que alguém tentar acessas alguma pasta do sistema que tenha a segurança garantida pelo Spring security, será apresentada a automaticamente a tela de login para a autenticação. Acesso a dados de usuários e permissões
Para que o Spring Security saiba quem são os usuários validos do sistema e suas permissões, poderemos informar quais são as SQLs que trazem essas informações do banco de dados. O Spring Security será configurado para utilizar a mesma conexão que o Hibernate utiliza. Instalação e configuração do SPRING SECURITY 1) Faça o Download do spring : http://static.springsource.org/spring security/site/downloads.html, a versão mais nova disponível é a 3.0, clique no link download. 2) A estrutura do arquivo obtido é a seguinte: spring security 3.0 +docs +dist 3) Dentro da pasta +dist, você encontrará o arquivo spring security samples contacts <versão>.war. 4) Extraia o arquivo spring security samples contacts <versão>.war e renomeie para.zip ( spring security samples contacts <versão>.zip),. 5) Dentro dele obtenha os arquivos jars do diretório WEB INF/lib, Copie esses arquivos para o diretório WEB INF/lib do projeto FinanceiroWeb, no Eclipse. Adaptação da conexão do Hibernate para o Spring: Atualmente a configuração do banco de dados está declarada no arquivo hibernate.cfg.xml, mas agora precisaremos que o Spring também se conecte ao banco de dados. Para evitar que seja necessário ter 2 arquivos de configuração de banco de dados para o mesmo projeto, vamos tirar essa configuração de dentro do Hibernate e compartilha la entre o Hibernate e o Spring. Para configurarmos um Data Source de conexões no projeto, será necessário criar o arquivo context.xml e alterar os arquivos web.xml e hibernate.cfg.xml. O arquivo contexto.xml permite que configurações sobre o aplicativo, que estariam no arquivo CATALINA_HOME\conf\server.xml, possam ser declaradas no próprio
aplicativo. Isso facilita a manutenção de tais configurações no ambiente de desenvolvimento. 6) O arquivo context.xml, deve ser criado em WebContent/META INF, conforme o exemplo a seguir : <?xml version="1.0" encoding="utf 8"?> <!DOCTYPE xml> <Context reloadable="true"> <Resource name="jdbc/financeirodb" auth="container" type="javax.sql.datasource" maxactive="100" maxidle="30" maxwait="10000" username="postgres" Nome no banco. password="root" Senha do Banco driverclassname="org.postgresql.driver" url="jdbc:postgresql://localhost:5432/bd"/> Caminho do banco </Contex 6.1) Alteração do Arquivo hibernate.cfg: <?xmlversion="1.0" encoding="utf-8"?> <!DOCTYPEhibernate-configurationPUBLIC"-//Hibernate/HibernateConfigurationDTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factoryname=""> <!-- <propertyname="hibernate.connection.driver_class">org.postgresql.driver</property> <propertyname="hibernate.connection.password">123456</property> <property name="hibernate.connection.url">jdbc:postgresql://localhost:5432/bd_financeiro_pf</prop erty> <propertyname="hibernate.connection.username">postgres</property> --> <propertyname="connection.datasource">java:comp/env/jdbc/financeirodb</property> <propertyname="hibernate.dialect">org.hibernate.dialect.postgresqldialect</property> <!----> <propertyname="current_session_context_class">thread</property> <propertyname="hibernate.hbm2ddl.auto">update</property> <!--UsandoasconfiguraçõesdoC3POparapooldeconexãov--> <propertyname="c3po.min_size">5</property> <propertyname="c3po.max_size">20</property> <propertyname="c3po.timeout">300</property>
<propertyname="c3po.max_statements">50</property> <propertyname="c3po.idle_test_period">3000</property> <!-- Configuraçõesdedebug--> <propertyname="show_sql">true</property> <propertyname="format_sql">true</property> <propertyname="generate_statistics">true</property> <propertyname="use_sql_comments">true</property> <!-- --> <mappingclass="org.financeiro.model.usuario.usuario"/> <mappingclass="org.financeiro.model.conta.conta"/> <mappingclass="financeiro.categoria.categoria"/> </session-factory> </hibernate-configuration> 7) O arquivo web.xml deve ser alterado, completo deverá ficar da seguinte forma : <?xml version="1.0" encoding="utf 8"?> <web app xmlns:xsi="http://www.w3.org/2001/xmlschema instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemalocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web app_3_0.xsd" id="webapp_id" version="3.0"> <display name>financeiroweb</display name> <welcome file list> <welcome file>index.xhtml</welcome file> </welcome file list> <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>*.xhtml</url pattern> </servlet mapping> <context param> <param name>javax.faces.datetimeconverter_default_timezone_is_system_ TIMEZONE</param name> <param value>true</param value> </context param> <! Spring Security >
<context param> (1) <param name>contextconfiglocation</param name> <param value> /WEB INF/applicationContext.xml /WEB INF/applicationContext security.xml </param value> </context param> <context param> <param name>com.sun.faces.expressionfactory</param name> <param value>com.sun.el.expressionfactoryimpl</param value> </context param> <filter> (2) <filter name>springsecurityfilterchain</filter name> <filter class>org.springframework.web.filter.delegatingfilterproxy</filter class> </filter> <filter mapping> (3) <filter name>springsecurityfilterchain</filter name> <url pattern>/*</url pattern> (4) </filter mapping> <listener> <listener class>org.springframework.web.context.contextloaderlistener</listener class> </listener>(5) <filter> <filter name>conexaofiter</filter name> <filter class>org.financeiro.web.filter.connectionfactoryfilter</filter class> </filter> <filter mapping> <filter name>conexaofiter</filter name> <url pattern>*.xhtml</url pattern> </filter mapping> <resource ref> <description>datasource Financeiro</description> <res ref name>jdbc/financeirodb</res ref name> <res type>java.sql.datasource</res type> <res auth>container</res auth> </resource ref> <servlet> <servlet name>resource Servlet</servlet name> <servlet class>org.primefaces.resource.resourceservlet</servlet class> <load on startup>1</load on startup> </servlet>
<servlet mapping> <servlet name>resource Servlet</servlet name> <url pattern>/primefaces_resource/*</url pattern> </servlet mapping> <context param> <param name>com.sun.faces.allowtextchildren</param name> <param value>true</param value> </context param> </web app> A configuração em (1), com o nome contextconfiglocation informa quais são os arquivos de configurações disponíveis. As configurações em (2) e (3), permitirão que o Spring Security intercepte todas as requisições realizadas, conforme explicado anteriormente. A configuração /* em <url pattern> (4), é o que faz com que todas as requisições sejam avaliadas. Se configuração fosse /*.jsp, somente os arquivos JSP seriam avaliados. A configuração em (5), permitirá que o Spring Security carregue os arquivos de configuração no momento em que o aplicativo web estiver sendo colocado no ar, junto com o servidor. 8) Crie o arquivo applicationcontext.xml dentro de WEB INF, conforme o exemplo a seguir: <?xml version="1.0" encoding="utf 8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/xmlschema instance" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring beans 3.0.xsd"> <bean id="financeirodatasource" (1) class="org.springframework.jndi.jndiobjectfactorybean"> <property name="jndiname"> <value>java:comp/env/jdbc/financeirodb</value> </property> </bean> </beans>
8.1) A configuração em (1), cria a referência financeirodatasource do tipo JndiObjectFactoryBean, apontando para o DataSourceJDNI jdbc/financeirodb. Essa referencia será utilizada dentro do próximo arquivo de configuração do Spring Security. 9) Dentro de WEB INF, crie o arquivo applicationcontext security.xml, da seguinte forma: <?xml version="1.0" encoding="utf 8"?> <b:beans xmlns="http://www.springframework.org/schema/security" xmlns:b="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/xmlschema instance" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring beans 3.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring security 3.0.xsd"> <http> (1) <intercept url pattern="/admin/**" access="role_administrador" /> (2) <intercept url pattern="/restrito/**" access="role_usuario" /> <form login login page="/publico/login.xhtml" (3) always use default target="true" default target url="/restrito/principal.xhtml" authentication failure url="/publico/login.xhtml?login_error=1" /> <logout/> (4) <remember me />(5) </http> <authentication manager> <authentication provider>(6) <jdbc user service data source ref="financeirodatasource"(7) authorities by username query="select u.login, p.permissao FROM usuario u, usuario_permissao p WHERE u.id = p.usuario AND u.login =?" users by username query="select login, senha, ativo FROM usuario WHERE login =?" /> </authentication provider> </authentication manager> </b:beans>
O elemento (1), é um agrupador das configurações referentes ao contexto web do sistema. A configuração de quais páginas ou diretórios que serão seguros é efetuada com o elemento (2), no qual o atributo pattern expressa o padrão textual da URL, e o atributo acess é uma linha separada por vírgula dos nomes de permissões que terão acesso ao recurso. O elemento (3), configura o funcionamento da página de Login do Spring Security. Nele é possível configurar os seguintes atributos: Login page Always use defalt target default target url authentication failure url O elemento (4), será utilizado para habilitar o recurso de logout para o sistema. Com o logout habilitado, basta chamar a URL/j_spring_security_logout para que o usuário seja direcionado para a página externa do sistema, tendo sua sessão invalidada. O elemento (5), é muito interessante, pois permite que, com a simples inserção de uma caixa de verificação, o login automático seja habilitado. A configuração que estiver definida em (6), dirá ao Spring quais são os usuários válidos do sistema e suas permissões. O elemento (7), permite declarar as SQLs que fornecerão os dados que o Spring Security necessita, vindas do banco de dados. Página Login <!DOCTYPEhtmlPUBLIC"-//W3C//DTDXHTML1.0Transitional//EN" "http://www.w3.org/tr/xhtml1/dtd/xhtml1-transitional.dtd"> <htmlxmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core"> <ui:compositiontemplate="/templates/interna.xhtml"> <ui:definename="corpo"> <h:body>
<br/> <br/> <br/> <divalign="center"> <h1>login</h1> <h:panelgrouprendered="#{!emptyparam.login_error}"> (2), <spanstyle="font-color:red">erroaoefetuarologin.</span><br/> <br/> Motivo:#{SPRING_SECURITY_LAST_EXCEPTION.message} </h:panelgroup> <formid="login"method="post" (3), action="${request.contextpath}/j_spring_security_check"> <table> <tr><td>login</td> <td><inputtype='text'name='j_username'(4), required="true"/></td></tr> <tr><td>senha</td> <td><inputtype='password'name='j_password' (5), required="true"/></td></tr> <tr><tdalign="right"><inputtype="checkbox" name="_spring_security_remember_me" onclick="if(!confirm('temcerteza?')) return false;"/></td> <td>entrarautomaticamente</td></tr> <tr><td> </td> <td><inputtype="submit" value="entrar"/></td> </tr> </table> <script> document.getelementbyid("login").j_username.value= "#{SPRING_SECURITY_LAST_USERNAME}";(6), </script> </form> </div> <br/> <br/> <divalign="center"> <h:form> <h:commandlinkvalue="registre-se" action="#{usuariobean.actionnovo}"/> </h:form> </div> </h:body> </ui:define> </ui:composition> </html> O conteúdo do bloco (2), só será exibido caso tenha ocorrido algum erro em uma tentativa de login anterior.
O formulário de login em sí só começa em (3),. A primeira coisa que perceber é que esse formulário não utiliza as tags <h:form> e sim <form> do HTML. Os campos do formulário tem nome padronizados pelo Spring Security (4). Habilitar o Login automático (5). O Login da última tentativa também está disponível em (6), que ultilizamos para sempre preencher o campo Login. Página Principal do usuário <!DOCTYPEhtmlPUBLIC"-//W3C//DTDXHTML1.0Transitional//EN" "http://www.w3.org/tr/xhtml1/dtd/xhtml1-transitional.dtd"> <htmlxmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:sec="http://www.springframework.org/security/facelets/tags">(1), <ui:compositiontemplate="/templates/interna.xhtml"> <ui:definename="corpo"> <h:body> <h:form> <divalign="right"> <a onclick="document.location='#{request.contextpath}/j_spring_security_logout'" title="sair"> <u><b>logout</b></u>(2), <h:graphicimagelibrary="imagens" name="logout16.png" style="border:0"/> </a> </div> </h:form> <divalign="center"> <divalign="left"> Usuariologado
</div> <divalign="left"> <h2>#{request.remoteuser},olá!</h2>(3), </div> <hr/> <h:form> </h:form> <h:form> <sec:ifanygrantedroles="role_usuario_vip"> <divalign="center"> <h3>usuáriovip!</h3> </div> </sec:ifanygranted> <sec:ifanygrantedroles="role_administrador">(4), <divalign="center"> <h2>bem-vindoadministrador!</h2> </div><br/> <u>administração</u><br/> <h:commandlinkaction="/admin/principal" title="administrativo"> <h:graphicimagelibrary="imagens" name="administrativo16.png"/> </h:commandlink> </sec:ifanygranted> </h:form> <br/> <h:form> <div> <h:commandbuttonvalue="contabancária" action="conta"/> <h:selectonemenuvalue="#{contextobean.contaativa.conta}" valuechangelistener="#{contextobean.setcontaativa}" rendered="#{!emptycontextoben}" onchange="submit()"> <f:selectitemsvalue="#{contabean.lista}" var="conta" itemvalue="#{conta.conta}" itemlabel="#{conta.descricao}"/> </h:selectonemenu> </div> </h:form> <br/> <br/> <h:form> <h:commandbuttonvalue="categorias" action="categoria.xhtml"/>
</h:form> </div> </h:body> </ui:define> </ui:composition> </html> (1), tags do Spring. (2), realizar logout. (3), retorna o login do usuário logado. (4), permite decidir para quais permissões seu conteúdo será exibido, ele faz uma verificação pra saber qual a permissão do usuário, nesse caso essa parte só aparece para o usuário com a permissão de administrador. Permissões Quando cadastrado no sistema, um usuário já recebe a permissão padrão que é de usuário. As demais permissões só o administrador pode dar. Também podemos dar permissão pelo banco de dados: Exemplo: INSERT INTO usuario_permissao(usuario,permissao) VALUES ('1','ROLE_ADMINISTRADOR'); No exemplo acima foi concedida a permissão de administrador para o usuário = 1. Exemplo: publicvoidsalvar(usuariousuario){ Longid=usuario.getId(); if(id==null id==0){ usuario.getpermissao().add("role_usuario"); usuariodao.salvar(usuario); CategoriaRNcategoriaRN=newCategoriaRN(); categoriarn.salvaestruturapadrao(usuario); }else{ usuariodao.atualizar(usuario); }
} Noexemploacimaousuárioésalvocompermissãousuário. O usuário administrador pode dar permissões de acordo com o exemplo: Figura 1.0
Exemplos Página de usuário com permissão padrão (somente usuário): OBS: Não tem acesso a administração Figura 1.1 Nesse exemplo o usuário não teve acesso ao link de administração porque é um usuário comum, a verificação é feita através do código: <sec:ifanygrantedroles="role_usuario"> <divalign="center"> <h2>bem-vindoadministrador!</h2> </div><br/> <u>administração</u><br/>
<h:commandlinkaction="/admin/principal" title="administrativo"> <h:graphicimagelibrary="imagens" name="administrativo16.png"/> </h:commandlink> </sec:ifanygranted> Usuário com permissão de administrador Figura 1.2 OBS: Usuário com permissão de administrador Página do usuário com permissão administrador (Listagem de usuários):
Figura 1.3 Nesse caso o usuário teve acesso a essa página de administração, porque como na página (figura 1.2) ele tem acesso ao ícone de administração, através de uma verificação que o SPRING fez através do código: <sec:ifanygrantedroles="role_administrador"> <divalign="center"> <h2>bem-vindoadministrador!</h2> </div><br/> <u>administração</u><br/> <h:commandlinkaction="/admin/principal" title="administrativo"> <h:graphicimagelibrary="imagens" name="administrativo16.png"/> </h:commandlink> </sec:ifanygranted> No exemplo acima o caminho para a administração <h:commandlink action="/admin/principal"title="administrativo">, Só aparecerá para o usuário com a permissão de administrador, devido a TAG seguinte: <sec:ifanygrantedroles="role_administrador"> </sec:ifanygranted> Então, tudo o que estiver dentro desse código será exibido apenas para o usuário com permissão de administrador.
Conclusão Concluímos que preparamos o sistema para ser mais seguro do ponto de vista de acesso de usuários. Além disso, tornamos exclusiva aos administradores a área administrativa do sistema, isso foi feita pela união dos recursos do Spring Security e pelo desenvolvimento JavaServerFaces, obtendo se uma estrutura segura e ao mesmo tempo amigável no ponto de vista funcional e ergonômico.