{"id":498,"date":"2015-08-15T02:53:26","date_gmt":"2015-08-15T05:53:26","guid":{"rendered":"https:\/\/www.erudio.com.br\/blog\/?p=498"},"modified":"2022-12-20T23:48:44","modified_gmt":"2022-12-21T02:48:44","slug":"iniciando-se-no-jsf-09-integrando-o-springsecurity-a-aplicacao-jsf","status":"publish","type":"post","link":"https:\/\/www.erudio.com.br\/blog\/iniciando-se-no-jsf-09-integrando-o-springsecurity-a-aplicacao-jsf\/","title":{"rendered":"Customizando o SpringSecurity"},"content":{"rendered":"<p>Salve rapaziada, este post era pra ter saido a um bom tempo junto com uma s\u00e9rie de posts sobre JSF entretanto a falta de tempo acabou impedindo que eu conclu\u00edsse esses posts.<\/p>\n<p>Provavelmente voc\u00ea deve estar pesquisando algo sobre o Spring Security 4 mas os conceitos centrais n\u00e3o mudaram da Spring Security 3.1.3.RELEASE para a vers\u00e3o 4.<\/p>\n<p>Quando trabalhamos com o Spring Security geralmente fazemos a autentica\u00e7\u00e3o de usu\u00e1rios na aplica\u00e7\u00e3o atrav\u00e9s do acesso \u00e0 base de dados ou atrav\u00e9s de web-servi\u00e7es ou de uma forma mais complicada atrav\u00e9s de uma mistura dos dois. Ent\u00e3o fica a pergunta e como eu fa\u00e7o para conseguir autenticar os usu\u00e1rios em cen\u00e1rios diferentes destes.<br \/>\nPodemos fazer como no agrad\u00e1vel exemplo abaixo em que autenticamos os usu\u00e1rios em mem\u00f3ria.<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n&lt;authentication-manager&gt;\n    &lt;authentication-provider&gt;\n      &lt;user-service&gt;\n        &lt;user name=&quot;eudes&quot; password=&quot;senhadoeudes&quot; authorities=&quot;ROLE_USER, ROLE_ADMIN&quot;&gt;\n        &lt;user name=&quot;gabriel&quot; password=&quot;senhadogabriel&quot; authorities=&quot;ROLE_USER&quot;&gt;\n\t\t&lt;user name=&quot;leandro&quot; password=&quot;senhadoleandro&quot; authorities=&quot;ROLE_USER&quot;&gt;\n\t\t&lt;user name=&quot;tiago&quot; password=&quot;senhadotiago&quot; authorities=&quot;ROLE_USER&quot;&gt;\n      &lt;\/user&gt;&lt;\/user&gt;&lt;\/user&gt;&lt;\/user&gt;&lt;\/user-service&gt;\n    &lt;\/authentication-provider&gt;\n  &lt;\/authentication-manager&gt;\n<\/pre>\n<p>Entretanto \u00e9 altamente improv\u00e1vel que o seu sistema s\u00f3 tenha alguns usu\u00e1rios cadastrados em modo hardcoded. O Spring Security nos prov\u00ea um kit de autentica\u00e7\u00e3o completo voltado para o banco de dados, mas \u00e9 preciso que a cria\u00e7\u00e3o e exist\u00eancia de tabelas estejam exatamente da forma requerida, o que nem sempre atende, assim, se quisermos autenticar, nossos usu\u00e1rios, atrav\u00e9s de web-services, estaremos, mais uma vez, presos ao kit padr\u00e3o do Spring Security.<br \/>\nA resposta para este tipo de problema est\u00e1 na personaliza\u00e7\u00e3o da <strong>AuthenticationProvider<\/strong> ou da <strong>UserDetailService<\/strong>. Se observarmos a <strong>UserDetails<\/strong> apenas verifica se um usu\u00e1rio existe ou n\u00e3o atrav\u00e9s de seu nome de usu\u00e1rio. Diante disso fica a pergunta apenas nome de usu\u00e1rio e senha s\u00e3o suficientes para garantir a seguran\u00e7a do sistema?<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\npublic UserDetails loadUserByUsername(String username)\n\tthrows UsernameNotFoundException {\n}\n<\/pre>\n<p>O que \u00e9 mais frustrante \u00e9 que voc\u00ea dificilmente encontra algum exemplo decente, explicando como extender a <strong>AuthenticationProvider<\/strong>, e a maioria dos exemplos lhe ensinam como implementar <strong>UserDetailService<\/strong>, entretanto de forma muito breve e simplificada.<br \/>\nAqui est\u00e3o as instru\u00e7\u00f5es faltantes at\u00e9 mesmo da documenta\u00e7\u00e3o Spring Security pois voc\u00ea certamente bateu bem a cabe\u00e7a at\u00e9 chegar a uma solu\u00e7\u00e3o que funcione seja ela atrav\u00e9s <strong>AuthenticationProvider<\/strong> ou da <strong>UserDetailService<\/strong>.<br \/>\nO que voc\u00ea definitivamente precisa \u00e9 personalizar <strong>AuthenticationProvider<\/strong>, que \u00e9 a classe base para realizar autentica\u00e7\u00e3o. Ent\u00e3o fica a pergunta por que a Spring Source n\u00e3o nos informa direito como implementar AuthenticationProvider ou a UserDetailService?<br \/>\nConferindo a classe <strong>AbstractUserDetailsAuthenticationProvider<\/strong>, que extende a <strong>AuthenticationProvider<\/strong>, podemos verificar um m\u00e9todo interessante:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\nprotected abstract UserDetails retrieveUser(java.lang.String username,\n\tUsernamePasswordAuthenticationToken authentication)\nthrows AuthenticationException\n<\/pre>\n<p>N\u00e3o \u00e9 exatamente isso o que a <strong>UserDetails<\/strong> e a <strong>UserDetailService<\/strong> nos fornece? Uma outra op\u00e7\u00e3o que temos \u00e9 estender <strong>AbstractUserDetailsAuthenticationProvider<\/strong> em vez da <strong>AuthenticationProvider<\/strong>, mas ainda assim <strong>UserDetailService<\/strong> \u00e9 muito mais popular.<br \/>\nVoc\u00ea pode simplesmente implementar <strong>UserDetailService<\/strong> para conseguir personalizar o seu processo de autentica\u00e7\u00e3o a partir de um banco de dados ou de um web-service bastando fornecer apenas um nome de usu\u00e1rio e senha para compar\u00e1-los com as informa\u00e7\u00f5es do usu\u00e1rio para conseguir a autentica\u00e7\u00e3o.<br \/>\nO que acontece no fim das contas \u00e9 que apenas fornecer um nome de usu\u00e1rio para o <strong>UserDetailService<\/strong>, \u00e9 o suficiente para retornar uma UserDetails que tem a senha do usu\u00e1rio, ent\u00e3o <strong>DaoAuthenticationProvider<\/strong> ser\u00e1 respons\u00e1vel por acessar o banco de dados e verificar as credenciais inseridas pelo usu\u00e1rio no formul\u00e1rio de login atrav\u00e9s da <strong>UserDetails<\/strong>.<br \/>\nEnfim encontrar o ponto certo de personaliza\u00e7\u00e3o \u00e9 importante, e um sinal de eleg\u00e2ncia no desenvolvimento de software.<br \/>\nO <strong>DaoAuthenticationProvider<\/strong> \u00e9 o <strong>AuthenticationProvider<\/strong> padr\u00e3o se no arquivo de configura\u00e7\u00e3o de autentica\u00e7\u00e3o &#8220;<strong>spring-security.xml<\/strong>&#8221; voc\u00ea n\u00e3o mencionar qualquer <strong>AuthenticationProvider<\/strong>, ent\u00e3o o <strong>Spring Security<\/strong> utiliza por padr\u00e3o o <strong>DaoAuthenticationProvider<\/strong>. Ent\u00e3o se voc\u00ea fizer assim:<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n&lt;authentication-manager&gt;\n    &lt;authentication-provider&gt;\n      &lt;user-service&gt;\n        &lt;user name=&quot;eudes&quot; password=&quot;senhadoeudes&quot; authorities=&quot;ROLE_USER, ROLE_ADMIN&quot;&gt;\n        &lt;user name=&quot;gabriel&quot; password=&quot;senhadogabriel&quot; authorities=&quot;ROLE_USER&quot;&gt;\n\t\t&lt;user name=&quot;leandro&quot; password=&quot;senhadoleandro&quot; authorities=&quot;ROLE_USER&quot;&gt;\n\t\t&lt;user name=&quot;tiago&quot; password=&quot;senhadotiago&quot; authorities=&quot;ROLE_USER&quot;&gt;\n      &lt;\/user&gt;&lt;\/user&gt;&lt;\/user&gt;&lt;\/user&gt;&lt;\/user-service&gt;\n    &lt;\/authentication-provider&gt;\n&lt;\/authentication-manager&gt;\n<\/pre>\n<p>Ele estar\u00e1 usando o <strong>DaoAuthenticationProvider<\/strong>.<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n&lt;authentication-manager&gt;\n\t&lt;authentication-provider user-service-ref=&quot;erudioUserService&quot;&gt;\n        &lt;\/authentication-provider&gt;\n    &lt;\/authentication-manager&gt;\n&lt;beans:bean id=&quot;erudioUserService&quot; class=&quot;com.cleancode.springmvc1.users.UserServiceImpl&quot;&gt;\n<\/pre>\n<p>Tamb\u00e9m no segundo caso, como \u00e9 padr\u00e3o, ele estar\u00e1 usando <strong>DaoAuthenticationProvider<\/strong>, mesmo que n\u00e3o esteja no seu arquivo de configura\u00e7\u00e3o.<\/p>\n<p>Agora vou lhe mostrar dois exemplos de como pode ser feito<\/p>\n<p><strong>Exemplo 1 Customiza\u00e7\u00e3o da AuthenticationProvider<\/strong>:<\/p>\n<p>No primeiro exemplo apenas comparo se a senha e o usu\u00e1rio digitados s\u00e3o iguais se sim ent\u00e3o o acesso \u00e9 liberado ao usu\u00e1rio. Obviamente em uma aplica\u00e7\u00e3o real voc\u00ea deve fazer algo mais s\u00e9rio que isso.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\npackage br.com.erudio.security;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport org.springframework.security.authentication.AuthenticationProvider;\nimport org.springframework.security.authentication.UsernamePasswordAuthenticationToken;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.core.AuthenticationException;\nimport org.springframework.security.core.GrantedAuthority;\nimport org.springframework.security.core.authority.GrantedAuthorityImpl;\n\npublic class CustomAuthenticationProvider implements AuthenticationProvider {\n\n    @Override\n    public Authentication authenticate(Authentication authentication) throws AuthenticationException {\n        System.out.println(&quot;O Login do cara \u00e9: &quot; + authentication.getName());\n        List&lt;grantedauthority&gt; auth = new ArrayList&lt;grantedauthority&gt;();\n        \/\/Use assim se voc\u00ea usa o Spring Security 3.0.5.RELEASE\n        auth.add(new GrantedAuthorityImpl(&quot;ROLE_USER&quot;));\n        \/\/J\u00e1 na vers\u00e3o 3.1.3.RELEASE essa classe foi depreciada e voc\u00ea deve usar como no trecho abaixo\n        \/\/auth.add(new SimpleGrantedAuthority(&quot;ROLE_USER&quot;));\n\n\t\t\/\/Nesse exemplo eu apenas comparo se o nome de usu\u00e1rio e senha s\u00e3o iguais.\n\t\t\/\/Caberia a voc\u00ea acessar os dados e fazer sua pr\u00f3pria regra de autentica\u00e7\u00e3o.\n        if (authentication.getName().equals(authentication.getCredentials())) {\n            return new UsernamePasswordAuthenticationToken(authentication.getName(), authentication.getCredentials(), auth);\n        } else {\n            return null;\n        }\n\n    }\n\n    @Override\n    public boolean supports(Class&lt;!--? extends Object--&gt; authentication) {\n        return authentication.equals(UsernamePasswordAuthenticationToken.class);\n    }\n}\n<\/pre>\n<p>No seu arquivo de configura\u00e7\u00e3o (<strong>spring-security.xml<\/strong>) voc\u00ea define um bean chamado <strong>customAuthenticationProvider<\/strong> especificando o pacote e o nome da classe ao qual ele se refere.<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n&lt;b:bean id=&quot;customAuthenticationProvider&quot; class=&quot;br.com.erudio.security.CustomAuthenticationProvider&quot;&gt;&lt;\/b:bean&gt;\n    &lt;authentication-manager&gt;\n        &lt;authentication-provider ref=&quot;customAuthenticationProvider&quot;&gt;\n    &lt;\/authentication-provider&gt;&lt;\/authentication-manager&gt;\n<\/pre>\n<p><strong>Exemplo 2 Customiza\u00e7\u00e3o da UserDetailsService<\/strong>:<\/p>\n<p>No exemplo abaixo estou usando nomes de usu\u00e1rio e senhas hardcoded como exemplo. Em uma aplica\u00e7\u00e3o real nesse ponto a \u00fanica coisa que voc\u00ea precisaria fazer \u00e9 acessar um banco de dados, servi\u00e7o ou web-service para recuperar as informa\u00e7\u00e7\u00f5es do usu\u00e1rio \u00e0 partir do nome de usu\u00e1rio, em seguida voc\u00ea cria uma inst\u00e2ncia de User e seta os valores de seu atributos de acordo com os dados do usu\u00e1rio, a senha s\u00f3 ser\u00e1 usada mais tarde pelo <strong>DaoAuthenticationProvider<\/strong><\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\npackage br.com.erudio.security;\n\nimport br.com.erudio.model.dao.HibernateDAO;\nimport br.com.erudio.model.dao.InterfaceDAO;\nimport br.com.erudio.model.entities.Pessoa;\nimport br.com.erudio.util.FacesContextUtil;\nimport java.io.Serializable;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport org.hibernate.Query;\nimport org.hibernate.Session;\nimport org.springframework.security.core.GrantedAuthority;\nimport org.springframework.security.core.authority.GrantedAuthorityImpl;\nimport org.springframework.security.core.userdetails.User;\nimport org.springframework.security.core.userdetails.UserDetails;\nimport org.springframework.security.core.userdetails.UserDetailsService;\nimport org.springframework.security.core.userdetails.UsernameNotFoundException;\nimport org.springframework.stereotype.Service;\n\n@Service(&quot;erudioUserService&quot;)\npublic class UserServiceImpl implements UserDetailsService, Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    @Override\n    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {\nList&lt;grantedauthority&gt; auth = new ArrayList&lt;grantedauthority&gt;();\n\n        if(username.equals(&quot;tiago&quot;))\n        {\n\n            auth.add(new SimpleGrantedAuthority(&quot;ROLE_ADMIN&quot;));\n            auth.add(new SimpleGrantedAuthority(&quot;ROLE_USER&quot;));\n\n\t\t\t\/\/Por padr\u00e3o no nosso exemplo o usu\u00e1rio e a senha s\u00e3o iguais\n            return new User(&quot;tiago&quot;,\n                    &quot;12fd5311017d4b8faf7abc6d7fa13d182f519a13&quot;,\n                     auth);\n\n        } else if (username.equals(&quot;gabriel&quot;)){\n\n            auth.add(new SimpleGrantedAuthority(&quot;ROLE_USER&quot;));\n            return new User(&quot;gabriel&quot;,\n                    &quot;18a98c35f49808b45edadc75fb1b25ebfd4037d6&quot;,\n                     auth);\n        }\n        else\n        {\n            throw new UsernameNotFoundException(&quot;Usu\u00e1rio n\u00e3o encontrado: &quot; + username);\n        }\n\n    }\n\n}\n<\/pre>\n<p>Por fim seu arquivo de configura\u00e7\u00e3o (<strong>spring-security.xml<\/strong>) deve se assemelhar ao trecho abaixo.<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n    &lt;authentication-manager&gt;\n        &lt;authentication-provider user-service-ref=&quot;erudioUserService&quot;&gt;\n            &lt;password-encoder hash=&quot;sha&quot;&gt;\n        &lt;\/password-encoder&gt;&lt;\/authentication-provider&gt;\n    &lt;\/authentication-manager&gt;\n    &lt;b:bean id=&quot;erudioUserService&quot; class=&quot;br.com.erudio.security.UserServiceImpl&quot;&gt;\n<\/pre>\n<p>Como voc\u00ea pode ver que voc\u00ea n\u00e3o precisa declarar o <strong>DaoAuthenticationProvider<\/strong> como <strong>AuthenticationProvider<\/strong>. Acesse o projeto no GitHub para ter uma vis\u00e3o mais abrangente.<\/p>\n<p>Divirta-se e bons c\u00f3digos sem bugs.<\/p>\n<h2>Treinamentos relacionados com este post<\/h2>\n<p><a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_rest_spring_java\" target=\"_blank\" rel=\"noopener\"><\/p>\n<p><img decoding=\"async\" style=\"max-width: 100%;\" title=\"REST API's RESTFul do 0 \u00e0  AWS com Spring Boot 3, Java e Docker\" src=\"https:\/\/raw.githubusercontent.com\/leandrocgsi\/blog-images\/main\/07-rest-spring-java.png\"><br \/>\n<\/a><\/p>\n<p><a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_microservices_java\" target=\"_blank\" rel=\"noopener\"><br \/>\n        <img decoding=\"async\" style=\"max-width: 100%;\" title=\"Microservices do 0 com Spring Cloud, Spring Boot e Docker\" src=\"https:\/\/raw.githubusercontent.com\/leandrocgsi\/blog-images\/main\/14-microservices-java.png\"><br \/>\n<\/a><\/p>\n<p><a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_rest_spring_kotlin\" target=\"_blank\" rel=\"noopener\"><br \/>\n        <img decoding=\"async\" style=\"max-width: 100%;\" title=\"REST API's RESTFul do 0 \u00e0 AWS com Spring Boot 3, Kotlin e Docker\" src=\"https:\/\/raw.githubusercontent.com\/leandrocgsi\/blog-images\/main\/18-rest-spring-kotlin.png\"><br \/>\n<\/a><\/p>\n<p><a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_ms_kotlin\" target=\"_blank\" rel=\"noopener\"><br \/>\n        <img decoding=\"async\" style=\"max-width: 100%;\" title=\"Microsservi\u00e7os do 0 com Spring Cloud, Kotlin e Docker\" src=\"https:\/\/raw.githubusercontent.com\/leandrocgsi\/blog-images\/main\/22-ms-kotlin.png\"><br \/>\n<\/a><\/p>\n<p><a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_docker\" target=\"_blank\" rel=\"noopener\"><br \/>\n        <img decoding=\"async\" style=\"max-width: 100%;\" title=\"Docker do 0 \u00e0 Maestria: Cont\u00eaineres Desmistificados mais 3 B\u00d4NUS\" src=\"https:\/\/raw.githubusercontent.com\/leandrocgsi\/blog-images\/main\/09-docker.png\"><br \/>\n<\/a><\/p>\n<p><a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_docker_para_aws\" target=\"_blank\" rel=\"noopener\"><br \/>\n        <img decoding=\"async\" style=\"max-width: 100%;\" title=\"Docker para Amazon AWS Implante Apps Java e .NET com Travis CI\" src=\"https:\/\/raw.githubusercontent.com\/leandrocgsi\/blog-images\/main\/10-docker-to-aws.png\"><br \/>\n<\/a><\/p>\n<p><a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_kotlin\" target=\"_blank\" rel=\"noopener\"><br \/>\n        <img decoding=\"async\" style=\"max-width: 100%;\" title=\"Kotlin para DEVs Java: Aprenda a Linguagem Padr\u00e3o do Android\" src=\"https:\/\/raw.githubusercontent.com\/leandrocgsi\/blog-images\/main\/20-kotlin.png\"><br \/>\n<\/a><\/p>\n<p><\/b:bean><\/grantedauthority><\/grantedauthority><\/grantedauthority><\/grantedauthority><\/beans:bean><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Salve rapaziada, este post era pra ter saido a um bom tempo junto com uma s\u00e9rie de posts sobre JSF entretanto a falta de tempo acabou impedindo que eu conclu\u00edsse esses posts. Provavelmente voc\u00ea deve estar pesquisando algo sobre o Spring Security 4 mas os conceitos centrais n\u00e3o mudaram da Spring Security 3.1.3.RELEASE para a [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[103,106,107],"tags":[],"_links":{"self":[{"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/posts\/498"}],"collection":[{"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/comments?post=498"}],"version-history":[{"count":3,"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/posts\/498\/revisions"}],"predecessor-version":[{"id":1483,"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/posts\/498\/revisions\/1483"}],"wp:attachment":[{"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/media?parent=498"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/categories?post=498"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/tags?post=498"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}