<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Murilo Alves on Medium]]></title>
        <description><![CDATA[Stories by Murilo Alves on Medium]]></description>
        <link>https://medium.com/@muriloalvesdev?source=rss-4f6cc8a554a9------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*6RBDhIPGJjrRJdnS65_OaQ.jpeg</url>
            <title>Stories by Murilo Alves on Medium</title>
            <link>https://medium.com/@muriloalvesdev?source=rss-4f6cc8a554a9------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Tue, 02 Jun 2026 22:05:38 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@muriloalvesdev/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Graceful Shutdown no Spring Boot]]></title>
            <link>https://muriloalvesdev.medium.com/graceful-shutdown-no-spring-boot-85c868493cd1?source=rss-4f6cc8a554a9------2</link>
            <guid isPermaLink="false">https://medium.com/p/85c868493cd1</guid>
            <category><![CDATA[spring-cloud]]></category>
            <category><![CDATA[graceful-shutdown]]></category>
            <category><![CDATA[shutdown]]></category>
            <category><![CDATA[spring-boot]]></category>
            <category><![CDATA[spring-graceful-shutdown]]></category>
            <dc:creator><![CDATA[Murilo Alves]]></dc:creator>
            <pubDate>Wed, 27 Aug 2025 16:55:40 GMT</pubDate>
            <atom:updated>2025-08-27T16:55:40.953Z</atom:updated>
            <content:encoded><![CDATA[<p>Em aplicações web modernas, o processo de desligar um servidor é tão crítico quanto iniciá-lo. Um encerramento abrupto durante uma transação importante ou uma requisição de longa duração pode resultar em perda de dados, erros inesperados ou uma experiência ruim para os usuários. É aqui que o graceful shutdown (desligamento gracioso) brilha, permitindo que sua aplicação finalize tarefas pendentes de forma controlada antes de se despedir. No Spring Boot, esse recurso é implementado de maneira robusta e configurável, tornando-o ideal para ambientes de produção. Neste artigo, exploraremos o que é o <strong>graceful shutdown</strong>, como configurá-lo no Spring Boot, melhores práticas e as atualizações mais recentes do framework até 2025.</p><h4>O Que é Graceful Shutdown e Por Que Ele é Importante?</h4><p>O graceful shutdown é um mecanismo que permite a um servidor web pausar a aceitação de novas requisições enquanto conclui as que estão em andamento, liberando recursos de forma ordenada. Embora não seja exclusivo do Spring Boot — sendo um conceito comum em servidores web e frameworks como <em>Node.js</em>, <em>Django</em> e <em>Quarkus</em> —, o Spring Boot oferece uma implementação poderosa e integrada ao seu ciclo de vida. Introduzido na versão 2.3 (2020), o <strong>graceful shutdown</strong> é essencial para aplicações em produção, especialmente em ambientes de microservices ou orquestrados por Kubernetes, onde atualizações e escalonamentos são frequentes.</p><p>Sem esse recurso, um desligamento forçado pode interromper requisições ativas, causar inconsistências em bancos de dados ou deixar conexões abertas, impactando a confiabilidade. Com o <strong>graceful shutdown</strong>, sua aplicação ganha um “<em>período de graça</em>” para finalizar tarefas, garantindo maior <strong>resiliência</strong> e uma manutenção mais suave.</p><h4>Como Funciona o Graceful Shutdown no Spring Boot</h4><p>O Spring Boot suporta o <strong>graceful shutdown</strong> para servidores web embutidos como <em>Tomcat</em>, <em>Jetty</em>, <em>Undertow</em> e <em>Netty</em>. Quando ativado, o processo segue estas etapas:</p><p><strong>1.</strong> <strong>Captura de Sinais de Shutdown</strong>: O Spring registra hooks na JVM para detectar sinais como <a href="https://pt.wikipedia.org/wiki/SIGTERM">SIGTERM</a>, comuns em containers <a href="https://www.docker.com/">Docker</a> ou pods <a href="https://kubernetes.io/pt-br/">Kubernetes</a>, iniciando um <strong>encerramento controlado</strong>.</p><p><strong>2.</strong> <strong>Bloqueio de Novas Requisições</strong>: O servidor para de aceitar novas conexões:</p><ul><li><em>Tomcat</em> e <em>Netty</em>: Rejeitam conexões no nível de rede.</li><li><em>Undertow</em>: Retorna HTTP 503 (Service Unavailable) para novas requisições.</li><li><em>Jetty</em>: Fecha novos sockets, mas permite conclusão de requisições ativas.</li></ul><p><strong>3.</strong> <strong>Conclusão de Requisições Ativas</strong>: Requisições em andamento têm um tempo limite configurável para finalizar. Se ultrapassarem, o shutdown prossegue, <strong>mas com liberação de recursos</strong>.</p><p><strong>4. Fechamento de Recursos</strong>: Beans com métodos <a href="https://docs.spring.io/spring-framework/reference/core/beans/annotation-config/postconstruct-and-predestroy-annotations.html">@PreDestroy</a> são invocados para liberar recursos como conexões de banco de dados, pools de threads ou clientes externos.</p><p>Esse processo é gerenciado pelo ciclo de vida do ApplicationContext, funcionando tanto em aplicações baseadas em Servlet quanto em aplicações reativas com WebFlux.</p><h4>Configurando o Graceful Shutdown</h4><p>A configuração no Spring Boot é simples e feita no arquivo <strong>application.properties</strong> ou <strong>application.yml</strong>. Exemplo em <strong>YAML</strong>:</p><pre>server:<br>  shutdown: graceful<br><br>spring:<br>  lifecycle:<br>    timeout-per-shutdown-phase: 45s</pre><ul><li><strong>server.shutdown</strong>: graceful: Ativa o modo gracioso (o default é immediate, que desliga instantaneamente).</li><li><strong>spring.lifecycle.timeout-per-shutdown-phase</strong>: Define o período de graça para conclusão de requisições (ex.: 10s para 10 segundos).</li></ul><p>Para testar, inicie sua aplicação, envie requisições e simule um shutdown com <em>kill -SIGTERM &lt;pid&gt;</em> ou <em>Ctrl+C</em>. Monitore os logs para verificar se as requisições ativas são concluídas e os recursos liberados corretamente.</p><p>Em ambientes orquestrados, como Kubernetes, combine com <strong>readiness probes</strong> para sinalizar que o pod não está mais pronto para receber tráfego, evitando requisições durante o shutdown. Ajuste o <strong>terminationGracePeriodSeconds</strong> no manifesto do pod para alinhar com o timeout configurado.</p><h4>Atualizações Recentes no Spring Boot (Até 2025)</h4><p>O <strong>graceful shutdown</strong> é um recurso consolidado desde o Spring Boot 2.3, mas melhorias incrementais nas versões 3.x e 4.x (2024–2025) trouxeram refinamentos:</p><ul><li><strong>Ciclo de Vida Aprimorado</strong>: O Spring Boot 3.3.x (2024) melhorou o <strong>DefaultLifecycleProcessor</strong>, garantindo uma ordem mais confiável na destruição de beans, especialmente para conexões Redis e RabbitMQ, evitando fechamentos prematuros.</li><li><strong>Suporte a WebFlux</strong>: Em aplicações reativas, o <strong>graceful shutdown</strong> agora lida melhor com fluxos assíncronos, mas operações longas podem exigir ajustes manuais de timeout para evitar bloqueios no <em>Netty</em>.</li><li><strong>Spring Boot 4.0-M2 (2025)</strong>: Focado em compatibilidade com Java 21 e Jakarta EE 10, não introduziu mudanças diretas no <strong>graceful shutdown</strong>, mas melhorias em dependências como <em>Tomcat</em> 10.1 e <em>Jetty</em> 12 otimizam a performance do shutdown.</li><li><strong>Spring Cloud</strong>: Em arquiteturas de microservices, o <strong>graceful shutdown</strong> agora integra melhor com balanceadores de carga, permitindo que serviços como Eureka marquem instâncias como “DOWN” antes do shutdown.</li></ul><p><em>Sempre consulte as notas de release da sua versão no repositório oficial do Spring Boot para detalhes específicos.</em></p><h4>Conclusão</h4><p>O <strong>graceful shutdown</strong> é uma prática indispensável para aplicações modernas, e o Spring Boot oferece uma implementação robusta e fácil de configurar. Com ajustes simples no <strong>application.yml</strong> e atenção a recursos personalizados, você garante que sua aplicação encerre com elegância, protegendo dados e usuários. À medida que o Spring Boot evolui, melhorias no ciclo de vida e suporte a novos servidores tornam o recurso ainda mais confiável.</p><p>Teste o <strong>graceful shutdown</strong> em seu próximo deploy e veja como ele eleva a confiabilidade da sua aplicação.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=85c868493cd1" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Protobuf — A Serialização Misteriosa]]></title>
            <link>https://muriloalvesdev.medium.com/protobuf-a-serializa%C3%A7%C3%A3o-misteriosa-afea2d59dcb6?source=rss-4f6cc8a554a9------2</link>
            <guid isPermaLink="false">https://medium.com/p/afea2d59dcb6</guid>
            <category><![CDATA[protobuf]]></category>
            <category><![CDATA[grpc]]></category>
            <category><![CDATA[protocol-buffers]]></category>
            <category><![CDATA[protobuf-and-grpc]]></category>
            <category><![CDATA[google-protobuf]]></category>
            <dc:creator><![CDATA[Murilo Alves]]></dc:creator>
            <pubDate>Fri, 04 Oct 2024 01:59:33 GMT</pubDate>
            <atom:updated>2024-10-04T01:59:33.178Z</atom:updated>
            <content:encoded><![CDATA[<h3>Protobuf — A Serialização Misteriosa</h3><blockquote>Este texto não é um tutorial, nem uma explicação técnica sobre Protobuf. É mais um convite para refletirmos juntos sobre os desafios e peculiaridades que enfrentamos com ele. Espero que vocês se identifiquem com esse sentimento e compreendam o que tentei expressar aqui.</blockquote><p><strong>ProtoBuff (Protocol Buffers)</strong> é, na essência, uma maneira eficiente de serializar dados, ou seja, transformar objetos em um formato que possa ser facilmente transmitido ou armazenado. Teoricamente, é a solução perfeita para lidar com grandes volumes de dados, substituindo formatos mais verbosos como XML ou JSON. Na prática, no entanto, essa “pitada de serialização misteriosa” é o que mantém a vida do desenvolvedor mais empolgante, rs.</p><p>A cada nova tecnologia, uma promessa: “isso vai facilitar sua vida.” Mas, como desenvolvedores, sabemos que toda escolha vem com suas peculiaridades. E é aqui que entra ProtoBuff, uma ferramenta poderosa de serialização que promete simplicidade, desempenho e economia de espaço. Mas, como qualquer tecnologia robusta, também vem com seus próprios enigmas.</p><h4>Primeiro desafio</h4><p>Lidar com ProtoBuff é como entrar em um clube exclusivo: só quem entendeu suas peculiaridades pode realmente apreciar sua beleza. ProtoBuff exige que você defina um esquema de dados, uma estrutura que mapeia o que pode ser transmitido ou recebido. Isso é fantástico para garantir que seu sistema tenha dados consistentes e bem organizados.</p><p>Além disso, há a “mágica” por trás da compactação de dados. Enquanto ProtoBuff realmente reduz o tamanho das mensagens transmitidas, o que é ótimo para desempenho, às vezes o resultado final parece uma caixa preta. Você envia um dado para o sistema e recebe algo que parece saído de um romance criptográfico. É neste momento que o desenvolvedor se depara com a realidade: “isso é incrível, mas como eu debugo isso?”.</p><p>Talvez essa seja a beleza de trabalhar com ProtoBuff. Ele te desafia. Ele não entrega tudo de bandeja. Cada vez que você encontra uma nova peculiaridade, você mergulha mais fundo na compreensão de como seus dados são processados e otimizados. E, no fim do dia, ao resolver aquele “mistério” técnico, a sensação de vitória é indescritível.</p><p>Então, sim, ProtoBuff é eficiente, é poderoso, mas, acima de tudo, traz uma camada de complexidade que faz com que o trabalho de serializar e desserializar dados seja mais do que uma tarefa técnica: torna-se uma pequena aventura. Afinal, a vida de um desenvolvedor seria bem menos emocionante sem essa pitada de serialização misteriosa.</p><p><strong>Mais sobre Protobuf</strong></p><p>Varda, K. Protocol Buffers: A Simple Way to Serialize Data. Google Developers, 2023. Disponível em: <a href="http://developers.google.com/protocol-buffers"><strong>developers.google.com/protocol-buffers</strong></a>. Um guia técnico oficial sobre o Protobuf, explicando seu funcionamento e aplicação em ambientes de alto desempenho como gRPC.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=afea2d59dcb6" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Hibernate Dynamic Update para colunas JSON — Exemplo em Java]]></title>
            <link>https://muriloalvesdev.medium.com/hibernate-dynamic-update-para-colunas-json-exemplo-em-java-3c829ce70186?source=rss-4f6cc8a554a9------2</link>
            <guid isPermaLink="false">https://medium.com/p/3c829ce70186</guid>
            <category><![CDATA[hibernate]]></category>
            <category><![CDATA[javahibernate]]></category>
            <category><![CDATA[dynamic-update]]></category>
            <category><![CDATA[hibernate-dynamic-update]]></category>
            <category><![CDATA[update-hibernate]]></category>
            <dc:creator><![CDATA[Murilo Alves]]></dc:creator>
            <pubDate>Wed, 18 Jan 2023 14:56:58 GMT</pubDate>
            <atom:updated>2023-01-18T14:56:58.626Z</atom:updated>
            <content:encoded><![CDATA[<h3>Hibernate Dynamic Update para colunas JSON — Exemplo em Java</h3><p>Utilizando o Hibernate Dynamic Update em entidades que contém mapeamento JSON em colunas de uma tabela.</p><p>Para fins didáticos, vamos utilizar a entidade <em>Product</em>. Utilizando Hibernate 6</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/958/1*l-Pvzr_Jtsn8vNfEb1Y3Kg.png" /><figcaption>Table product</figcaption></figure><blockquote>Disclaimer</blockquote><blockquote>Hibernate ORM não contém suporte para colunas do tipo JSON, então nesse exemplo estou utilizando a lib <a href="https://github.com/vladmihalcea/hypersistence-utils">Hypersistence Utils</a>, que fornece um JsonType que permite mapear objetos como String, Map, List, JsonNode ou Pojos em colunas colunas JSON, indepedente de banco de dados (PostgreSQL, MySQL ou H2 por exemplo).</blockquote><p>Continuando..</p><p>A coluna <em>properties</em> da nossa tabela nesse exemplo está sendo mapeada como <strong>jsonb</strong> do PostgreSQL, por isso utiliza o <strong>JsonType</strong> da lib mencionada acima.</p><h4>Problema</h4><p>Quando atualizamos uma entidade do Hibernate sem o Dynamic Update, por padrão, após modificar uma entidade</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/924/1*BdyW6DcW-q86KrC7NSis_A.png" /><figcaption>Update Product entity</figcaption></figure><p>O Hibernate executa uma instrução UPDATE que inclui todos os atributos da entidade, mesmo que eles não tenham sido modificados</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vHnym6Wvzfyi26qHpQ_aug.png" /><figcaption>Instruction without solution executed by hibernate</figcaption></figure><p>Analisando a instrução executada podemos ver que o atributo <em>properties</em> da tabela <em>product</em> também foi incluído, ou seja, quanto maior o objeto JSON, maior será o impacto no desempenho da execução, pois está enviando dados desnecessários.</p><p><strong>Solução</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/692/1*m5xG6Ljedgqw37Ab4FewRw.png" /><figcaption>Annotation @DynamicUpdate</figcaption></figure><p>A anotação <strong>@DynamicUpdate</strong> garante que o Hibernate utilize apenas as colunas alteradas na instrução SQL, ou seja</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/658/1*OfTczJCZz0UIAbYNmHYeTw.png" /><figcaption>Instruction with solution executed by hibernate</figcaption></figure><p>Muito melhor, concorda? Então concordamos que sempre devemos utilizar essa anotação &quot;mágica&quot;, certo? Errado!</p><p>Acabamos de ver os prós e concordamos que uma instrução SQL gigante que contenha colunas JSON gigantescas podem se beneficiar com o Hibernate Dynamic Update</p><p><strong>Como o Hibernate Dynamic Update funciona</strong></p><p>Primeiro precisamos saber que o Hibernate utiliza um sistema de cache para gerar as atualizações SQL, mas quando usamos a anotação <strong>@DynamicUpdate,</strong> o Hibernate precisa gerar uma nova instrução SQL. Este SQL gerado inclui apenas as colunas alteradas.</p><p>O Hibernate precisa identificar o estado da entidade atual para descobrir quais colunas foram alteradas, ou seja, quando alteramos qualquer campo de uma entidade, ela compara os estados <strong>atual</strong> e <strong>modificado</strong> para saber quais campos foram alterados.</p><p><strong>Conclusão</strong></p><p>Saber quando utilizá-lo é imprescindível.</p><p><strong>Referência</strong></p><ul><li><a href="https://thorben-janssen.com/dynamic-inserts-and-updates-with-spring-data-jpa/">https://thorben-janssen.com/dynamic-inserts-and-updates-with-spring-data-jpa/</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3c829ce70186" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Autenticação vs Autorização]]></title>
            <link>https://muriloalvesdev.medium.com/autentica%C3%A7%C3%A3o-vs-autoriza%C3%A7%C3%A3o-bd7bd533ca7a?source=rss-4f6cc8a554a9------2</link>
            <guid isPermaLink="false">https://medium.com/p/bd7bd533ca7a</guid>
            <category><![CDATA[auth]]></category>
            <category><![CDATA[authorization]]></category>
            <category><![CDATA[authentication]]></category>
            <dc:creator><![CDATA[Murilo Alves]]></dc:creator>
            <pubDate>Mon, 16 Jan 2023 14:23:10 GMT</pubDate>
            <atom:updated>2023-01-16T19:02:07.038Z</atom:updated>
            <content:encoded><![CDATA[<p>Entenda de uma vez por todas a diferença entre autenticação e autorização.</p><h4>O que vem primeiro autorização ou autenticação</h4><p>Não podemos autorizar um usuário ou serviço antes de identificá-lo, ou seja, a autenticação sempre vem antes da autorização.</p><h4>Semelhanças</h4><p>Autenticação e autorização são semelhantes porque são duas partes implícitas do processo que fornecem acesso. Com isto, ambos são confundidos, um dos motivos de serem confundidos é que compartilham a mesma abreviação <strong>auth</strong>.</p><h4>Diferenças</h4><p>Autenticação e Autorização podem ter semelhanças, <strong>mas cada uma tem um papel diferente na proteção de uma aplicação</strong>. Um verifica uma identidade <strong>antes de conceder acesso</strong>, enquanto o outro usa essa <strong>identidade verificada para controlar o acesso</strong>.</p><p>Vamos ver um exemplo com um cenário bem básico?</p><p>Digamos que você esteja indo visitar um parente bem próximo. Ao chegar, você toca o interfone e seu parente te reconhece (autenticação), como seu parente lhe reconheceu (autenticou), o mesmo permite deixá-lo entrar em sua casa. Porém, com base no seu nível de relacionamento, existem certas coisas que você pode e outras não (autorização). Por exemplo, você pode entrar na sala de estar, mas não pode entrar no escritório particular do seu parente, ou seja, você tem autorização para entrar na cozinha, mas é proibido o acesso ao escritório particular.</p><h4>Alguns tipos de autenticação</h4><p>O mais comum, para verificar a identidade de um usuário, os processos de autenticação utilizam algo que o usuário — <strong>tem</strong> — <strong>sabe</strong>, por exemplo:</p><p>Na categoria:</p><p>— <strong>você sabe</strong> <em>senhas</em> e <em>perguntas</em> de segurança são fatores de autenticação.</p><p>— <strong>você tem</strong> tokens de segurança USB, celular e outros dispositivos físicos são fatores de autenticação.</p><h4>Alguns tipos de autorização</h4><p>Toda aplicação têm (ou deveria ter) um controle de acesso aplicando regras de permissão com base no nível de autorização do usuário, por exemplo, geralmente existem usuários comuns e/ou administradores. Se um usuário padrão quer deletar algo, possivelmente seu acesso será negado, mas os administradores têm autorização para realizar esse tipo de alteração.</p><p>Outro tipo comum é o controle de acesso aos dados, usuários comuns tem visibilidade de dados que normalmente são públicos e que podem ser expostos, já usuários administradores conseguem visualizar dados confidenciais. Neste exemplo, a autorização determina quais usuários podem acessar os diversos tipos de dados.</p><h4>Controle de acesso</h4><p>A autorização define políticas sobre o que um usuário ou serviço pode acessar. O controle de acesso impõe essas políticas.</p><p>Embora muitas políticas de autorização façam parte do controle de acesso, o controle de acesso é um componente da autorização. O controle de acesso utiliza o processo de autorização para conceder ou negar acesso a aplicação ou aos dados da mesma.</p><p>Se compararmos autenticação e controle de acesso, a comparação entre autenticação e autorização ainda se aplica. A autenticação verifica a identidade do usuário e o controle de acesso usa essa identidade para conceder ou negar acesso.</p><h4>Referências</h4><ul><li><a href="https://auth0.com/docs/get-started/identity-fundamentals/authentication-and-authorization">Auth0</a></li><li><a href="https://www.javatpoint.com/authentication-vs-authorization">Javapoint</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=bd7bd533ca7a" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Proteja suas APIs REST Spring Boot com Keycloak]]></title>
            <link>https://muriloalvesdev.medium.com/proteja-suas-apis-rest-spring-boot-com-keycloak-d6a7fb225db4?source=rss-4f6cc8a554a9------2</link>
            <guid isPermaLink="false">https://medium.com/p/d6a7fb225db4</guid>
            <category><![CDATA[docker-container]]></category>
            <category><![CDATA[keycloak-configuration]]></category>
            <category><![CDATA[docker]]></category>
            <category><![CDATA[docker-image]]></category>
            <category><![CDATA[keycloak]]></category>
            <dc:creator><![CDATA[Murilo Alves]]></dc:creator>
            <pubDate>Thu, 10 Jun 2021 23:55:45 GMT</pubDate>
            <atom:updated>2021-06-10T23:55:45.583Z</atom:updated>
            <content:encoded><![CDATA[<h3>Keycloak — Resumo</h3><p>A Keycloak é um produto open source da Red Hat, cuja versão enterprise é o Red Hat Single Sign-On, que permite o login único com o Gerenciamento de Identidades e Gerenciamento de Acesso, destinado a aplicativos e serviços modernos. Em vez de fazer login em aplicativos individuais, os usuários se autenticam no Keycloak.</p><p>O foco principal deste resumo completo é adicionar segurança a APIs REST Spring Boot com Keycloak Spring Boot Adapter.</p><p>Keycloak oferece alguns recursos como,</p><h4><strong>1.</strong> Suporte para <a href="https://pt.wikipedia.org/wiki/OpenID">OpenID Connect</a>, <a href="https://imasters.com.br/desenvolvimento/como-funciona-o-protocolo-oauth-2-0">OAuth 2.0</a> e <a href="https://en.wikipedia.org/wiki/Security_Assertion_Markup_Language">SAML</a>.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/397/0*Xne_Vcp78OMlXdOc.png" /></figure><h4><strong>2.</strong> Single Sign-On</h4><p>Suas aplicações não tem a necessidade de lidar com armazenamentos de usuários, armazenamento de credenciais, autenticação, formulários de login ou gerenciamento de sessão.</p><p>Com o recurso <a href="https://en.wikipedia.org/wiki/Single_sign-on">Single Sign-On</a>, uma vez que um usuário faz login no Keycloak, os usuários não precisam fazer login novamente para acessar uma aplicação diferente e o mesmo se aplica ao logout.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*b-qvrkVL3JB4T-ka.png" /></figure><h4>3. Federação do usuário</h4><p>Keycloak possui suporte integrado para conectar-se a servidores <a href="https://help.blackboard.com/pt-br/Learn/Administrator/SaaS/Authentication/Implement_Authentication/LDAP_Authentication_Provider_Type#:~:text=LDAP%20(Lightweight%20Directory%20Access%20Protocol,informa%C3%A7%C3%B5es%20e%20recuperar%20as%20informa%C3%A7%C3%B5es.">LDAP</a> ou Active Directory existentes.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*aN-dk2WJRXkdJUjb.png" /></figure><h4>4. Provedores de identidade</h4><p>O Keycloak pode autenticar usuários com provedores de identidade OpenID Connect ou SAML 2.0 configurando o mesmo por meio do console de administração. Além disso, sem código, seus aplicativos podem ser integrados a redes sociais como Facebook, Google, Microsoft, GitHub entre outros.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*YcQwKl3hTWol9eXB.png" /></figure><h4>5. Serviços de autorização</h4><p>Keycloak fornece autorização para gerenciar permissões para todos os serviços, usuários e grupos.</p><p>As funções podem ser definidas com o console de administração, bem como por meio de APIs, SDK.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/923/0*7ZJWlTBQkFkaPvdZ.png" /></figure><h3>Keycloak — Instalação</h3><p>Existem algumas formas de se instalar o Keycloak. Neste artigo vou mostrar como instalar o Keycloak utilizando Docker.</p><h4>Keycloak — Instalação com Docker</h4><p>1. Garanta que tenha o Docker instalado em seu computador. <a href="https://docs.docker.com/get-docker/">Doc. Docker</a>.</p><p>2. Abra seu Terminal e execute o seguinte comando. Substitua os campos <em>&lt;username&gt;</em>e <em>&lt;password&gt;</em>no comando abaixo, que será o nome de usuário e senha do administrador inicial.</p><pre>docker run -p 8080:8080 -e KEYCLOAK_USER=<em>&lt;username&gt;</em> -e KEYCLOAK_PASSWORD=<em>&lt;password&gt;</em> quay.io/keycloak/keycloak:13.0.1</pre><p>Existem várias variáveis ​​de ambiente disponíveis para configurações Keycloak adicionais, como integração com alguns bancos de dados (MySQL, PostgreSQL, MariaDB, Oracle, Microsoft SQL Server), Importar/Exportar Realms, Temas Personalizados, Provedores Personalizados, Clustering e muito mais.</p><h3>Keycloak — Configuração</h3><h4>Criar Realm</h4><p>Um <strong>Realm</strong> gerencia um conjunto de usuários, credenciais, funções e grupos. Um usuário pertence e efetua login em um domínio. Os <strong>realms</strong> são isolados uns dos outros e só podem gerenciar e autenticar os usuários que controlam.</p><p>1. Vá para <a href="http://localhost:8080/auth/admin/">http://localhost:8080/auth/admin/</a> e faça login no Keycloak Admin Console usando as credenciais de administrador que você adicionou ao executar o comando Docker no tópico anterior.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/577/1*Kl-fhIMXvtr-Ofh7c2e5rw.png" /></figure><p>2. Clique menu suspenso <strong>Master</strong> localizado do lado esquerdo de sua tela e em seguida clique em <strong>Add Realm</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/804/0*REpfIY0a7QIp0j8x.png" /></figure><p>Quando você está conectado ao domínio <strong>master</strong>, este menu suspenso exibe todos os domínios existentes. Quando o domínio é criado, a página principal do console de administração é aberta. Observe que o domínio atual agora está definido como <strong>Demo</strong>, clique em <strong>Create</strong>.</p><p>Alterne entre o gerenciamento do domínio <strong>Master</strong> para o domínio que você acabou de criar, passe o mouse sobre o domínio <strong>Master</strong>,</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/223/1*Lr1OWXEq2dAGQXkKANu38g.png" /></figure><p>E selecione o domínio <strong>Demo</strong>,</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/220/1*9fzoiGJHh_Oj2NbvfWC9Hw.png" /></figure><p>Certifique-se de que <strong>Demo</strong> está selecionado para as configurações abaixo. Evite usar o domínio <strong>Master</strong>. Você não precisa criar um <strong>Realm</strong> todas as vezes. É um processo único.</p><h4>Criar Cliente</h4><p>Os clientes são entidades que podem solicitar que o Keycloak autentique um usuário. Na maioria das vezes, os clientes são aplicativos e serviços que desejam usar o Keycloak para se proteger e fornecer uma solução de logon único.</p><p>Os clientes também podem ser entidades que desejam apenas solicitar informações de identidade ou um token de acesso para que possam invocar com segurança outros serviços na rede protegidos pelo Keycloak.</p><p>1. Clique no menu <strong>Clients</strong> no painel esquerdo. Todos os clientes disponíveis para o <strong>Realm</strong> selecionado <em>(Demo)</em> serão listados neste menu.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6s7SfzBvathonxzM68F_PQ.png" /></figure><p>2. Para criar um novo cliente, clique em <strong>Create</strong> . Você será solicitado a fornecer um <strong>ID de cliente</strong>, um <strong>protocolo de cliente</strong> e uma <strong>URL raiz</strong>.</p><p>Uma boa escolha para o ID do cliente é o nome do seu aplicativo <em>(demo-springboot-with-keycloak)</em>, o protocolo do cliente deve ser definido como <strong>openid-connecte</strong> o URL raiz deve ser definido como o <strong>URL da aplicação </strong>e como estamos testando localmente neste exemplo, vou adicionar a URL raiz como localhost.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/986/1*YZ5nptPS3LCwbZspUv_F8Q.png" /></figure><p>3. Após de salvar o cliente, será exibida a página de configuração do mesmo, onde você pode atribuir um nome e uma descrição ao cliente, se desejar.</p><p>Defina o <strong>Access Type </strong>como <strong>confidential</strong>,</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/239/1*pqlqktn5OtEAHmjNszhTpg.png" /></figure><p><strong>Authorization Enable</strong> para <strong>ON</strong>,</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/262/1*ug0XP-Dnh-VXb_tnwEd2bQ.png" /></figure><p><strong>Service Accounts Enable </strong>para <strong>ON,</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/278/1*I_GVqCNrEuQ_rH6oykLVcg.png" /></figure><p>e clique em <strong>Save</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/843/1*xheMVWTzcMv_WfvJQZXsYQ.png" /></figure><p>4. Clique na aba <strong>Credentials</strong> que mostrará o <strong>Client Secret</strong> que é necessário para as configurações do Spring Boot Application Keycloak.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*HOkm_rp3dpU6CS-PT8IR7Q.png" /></figure><p>Agora clique na aba <strong>Roles</strong> para criar as roles do cliente. Imagine que a aplicação com o qual você está construindo tenha diferentes tipos de usuários com diferentes permissões de usuário. Ex: usuários e administradores.</p><ul><li>Algumas APIs só podem ser acessadas por usuários.</li><li>Algumas APIs podem ser acessadas apenas por administradores.</li><li>Algumas APIs podem ser acessadas por usuários e administradores.</li></ul><p>Então, vamos criar duas roles: <em>user</em> e <em>admin</em>. Clique no botão add role localizado na lateral direita de sua tela,</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*nmdSYj21V5jX-47XX6vsDw.png" /></figure><p><strong>Crie a role user,</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6yWgNIcQYJP67c2D6NYu2Q.png" /></figure><p><strong>Crie a Role admin,</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VjBNaFfY7y4W_Jt5ZCiS3Q.png" /></figure><p><strong>Roles cadastradas,</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ZEsYCTgR9RyhKwg98rNteA.png" /></figure><h4>Criar Roles de Realm</h4><p>As aplicações geralmente atribuem acesso e permissões a roles específicas, em vez de usuários individuais, pois lidar com usuários pode ser muito trabalhoso e difícil de gerenciar.</p><p>Vamos criar <strong>app-user</strong> e <strong>app-admin</strong> <strong>Realm</strong> <strong>Roles</strong> atribuindo <em>demo-springboot-with-keycloak</em> roles correspondentes (user, admin).</p><ol><li>Clique no menu Roles no painel esquerdo. Todas as roles disponíveis para o Realm selecionado serão exibidas,</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vMsJ8pDDwtrUhPMDrfZ-ZQ.png" /></figure><p>2. Para criar uma role <strong>app-user</strong> de role, clique em <strong>Add Role</strong> localizado na lateral direita de sua tela. Você será solicitado a fornecer um nome para a role e uma descrição . Forneça os detalhes abaixo e salve.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*wy8gtth8d2JYL1Zmvrc5fg.png" /></figure><p>Após salvar, habilite <strong>Composite Roles</strong> para <strong>ON</strong> e pesquise por <em>demo-springboot-with-keycloak </em>no campo <strong>Client Roles</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/831/1*jnN0fQJXhWWcvYsPlYndPQ.png" /></figure><p><strong>Selecione a role user</strong> de <em>demo-springboot-with-keycloak </em>e clique em <strong>Add Selected&gt;</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/601/1*tH0Su4ctYkp3hXBcNfcYRQ.png" /></figure><p>Esta configuração atribuirá a <em>demo-springboot-with-keycloak</em> a role <strong>user</strong> de cliente à role de <strong>app-user</strong>. Se você tiver vários clientes com várias funções, escolha as funções necessárias de cada cliente para criar funções de domínio com base na necessidade.</p><p>3. Realize os mesmos passos para criar o <strong>app-admin</strong>, mas atribua a <strong>role admin</strong> do cliente em vez da <strong>role user</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/799/1*4uatY6A5oIpgmGo-cZZUpg.png" /></figure><h4>Criar Usuários</h4><p>Vamos criar seguintes usuários e conceder-lhes <strong>app-user</strong> e <strong>app-admin</strong> para realizarmos os testes.</p><ul><li>funcionario1 com app-user Realm Role.</li><li>funcionario2 com app-admin Realm Role.</li><li>funcionario3 com funções de app-user &amp; app-admin Realm Roles.</li></ul><ol><li>No menu, clique em <strong>Users</strong> para exibir a página da lista de usuários.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ADXyHFX6v0o_qSqsH-1jpg.png" /></figure><p>2. No lado direito da lista de usuários vazia, clique em <strong>Add User</strong>.</p><p>3. Informe o <strong>username</strong>; este é o único campo obrigatório.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/773/1*WgF13RcYNGshyFzYV0IVlw.png" /></figure><p>3.1 Habilite o botão <strong>Email Verified</strong> de OFF para <strong>ON</strong> e clique em <strong>Save</strong> para salvar os dados e abrir a página de gerenciamento para o novo usuário.</p><p>4. Clique na aba <strong>Credentials</strong> para definir uma senha temporária para o novo usuário.</p><p>5. Digite uma nova senha e confirme-a. Mude o botão <strong>Temporary</strong> de ON para <strong>OFF</strong> e clique em <strong>Set Password</strong> para definir a senha do usuário para a nova que você informou. Para simplificar, vamos definir a senha <em>mypassword</em> para todos os usuários.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*QfduwgttXNYddd-f7MSzZg.png" /></figure><p>6. Clique na guia <strong>Role Mappings</strong> para atribuir <strong>Realm Roles</strong> ao usuário. A lista de roles do realm estará disponível na lista de <strong>Available Roles,</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*QfduwgttXNYddd-f7MSzZg.png" /></figure><p>Selecione uma role necessária e clique em <strong>Add Selected&gt;</strong> para atribuí-la ao usuário,</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/930/1*LZ-qz0Nzf32jkl8NQQA1mQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/887/1*fV1QYjG7bS1zHu2tRyddpQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/887/1*rZTcwHPwoEmNEDtEybG6Mg.png" /></figure><p>Acredito que tenha achado um pouco complicado passar por todas as configurações. Mas quando você começar a utilizar o Keycloak com mais frequência, essas configurações se tornarão muito simples.</p><h4>Gerar Tokens</h4><p>Agora vamos aprender como gerar um <em>token</em> de acesso para usuários do Keycloak.</p><ol><li>Vá para o menu <strong>Realm Settings </strong>do domínio <strong>Demo</strong> no menu à esquerda,</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/221/1*F4WqgUN5Xcjf8qQs3zJHdQ.png" /></figure><p>No campo <strong>Endpoints</strong> clique em <strong>OpenID Endpoint Configuration,</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/938/1*aMAe9Qpadd4jFOZBdnnPgA.png" /></figure><p><a href="http://localhost:8080/auth/realms/Demo/.well-known/openid-configuration">Para visualizar os detalhes</a> do <strong>OpenID Endpoint,</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LUAgJj1Z1Y9PYo3esWGV7A.png" /></figure><p>2. Copie <strong>token_endpoint</strong> da <strong>OpenID Endpoint Configuration</strong>. A URL seria semelhante a:</p><pre>&lt;KEYCLOAK_SERVER_URL&gt;/auth/realms/&lt;REALM_NAME&gt;/protocol/openid-connect/token</pre><pre>Ex: <a href="http://localhost:8080/auth/realms/Demo/protocol/openid-connect/token">http://localhost:8080/auth/realms/Demo/protocol/openid-connect/token</a></pre><p>3. Use o seguinte comando <a href="https://curl.se/docs/manpage.html"><strong>CURL</strong></a> para gerar as credenciais do usuário. Substituir <strong>KEYCLOAK_SERVER_URL</strong>, <strong>REALM_NAME</strong>, <strong>CLIENT_ID</strong>, <strong>CLIENT_SECRET</strong>, <strong>USERNAME</strong>, <strong>PASSWORD</strong>,</p><pre>curl -X POST &#39;&lt;KEYCLOAK_SERVER_URL&gt;/auth/realms/&lt;REALM_NAME&gt;/protocol/openid-connect/token&#39; \<br> --header &#39;Content-Type: application/x-www-form-urlencoded&#39; \<br> --data-urlencode &#39;grant_type=password&#39; \<br> --data-urlencode &#39;client_id=&lt;CLIENT_ID&gt;&#39; \<br> --data-urlencode &#39;client_secret=&lt;CLIENT_SECRET&gt;&#39; \<br> --data-urlencode &#39;username=&lt;USERNAME&gt;&#39; \<br> --data-urlencode &#39;password=&lt;PASSWORD&gt;&#39;</pre><p>Exemplo,</p><pre>curl -X POST &#39;<a href="http://localhost:8080/auth/realms/Demo/protocol/openid-connect/token&#39;">http://localhost:8080/auth/realms/Demo/protocol/openid-connect/token&#39;</a> \<br> --header &#39;Content-Type: application/x-www-form-urlencoded&#39; \<br> --data-urlencode &#39;grant_type=password&#39; \<br> --data-urlencode &#39;client_id=demo-springboot-with-keycloak&#39; \<br> --data-urlencode &#39;client_secret=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx&#39; \<br> --data-urlencode &#39;username=funcionario1&#39; \<br> --data-urlencode &#39;password=mypassword&#39;</pre><p><em>Caso tenha se esquecido, o </em><strong>client_secret</strong><em> se localiza no Menu </em><strong>Clients</strong><em>, após acessar este menu clique em </em><strong>demo-springboot-with-keycloak</strong><em> e vá até a aba </em><strong>Credentials</strong><em>, veja,</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fPNgoXT5WeN3bWwRrY6_pg.png" /><figcaption>Secret</figcaption></figure><p>Execute o <strong>CURL</strong> do Terminal ou use o <strong>Postman</strong>. Veja a resposta da requisição feita no <strong>Postman,</strong></p><p>Request,</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*WBaFagYJRO-bocGaMgxZ7w.png" /></figure><p>Response,</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*RgbDDDfiTesZIpnfpinUNg.png" /></figure><p>Vamos decrypt o token <strong>access_token</strong> <strong>JWT</strong> emitido para que o funcionario1 possa utilizar. <a href="https://jwt.io">Clique aqui</a>.</p><ul><li><strong>access_token</strong> contém os detalhes da permissão do usuário.</li><li><strong>realm_access.roles</strong> contém <strong>app_user</strong> <strong>realm role</strong>.</li><li><strong>resource_access</strong>.demo-springboot-with-keycloak.roles contém a user roles do cliente.</li><li><strong>preferred_username</strong> contém o nome de usuário do usuário (funcionario1)</li></ul><p>Veja o payload,</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/427/1*xAsYxSYYtPSTSsg5A-m4Ww.png" /></figure><ul><li><strong>iat</strong>, <strong>exp,</strong></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/157/1*WNSwSkRQmg2bG4We-SW7DA.png" /></figure><p>Contém o tempo de emissão do token, bem como o tempo de expiração do mesmo. Os tempos de expiração do token de acesso podem ser personalizáveis ​​em <strong>Realm Settings</strong>,</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/207/1*hTCK6prgGboNoAxC-6b_SA.png" /></figure><p>Aba <strong>Tokens,</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/951/1*AmuMo3ae5z5shICSNI6GIw.png" /></figure><p>Por padrão, o <strong>Access Token Lifespan</strong> seria definido para 5 minutos, que pode ser personalizado com base em seus requisitos de segurança.</p><p>Na fase de teste da aplicação com Spring Boot, use as etapas acima para gerar tokens de acesso para vários usuários com as credenciais de usuário correspondentes. Além disso, se o token expirar, gere um novo token com o mesmo processo.</p><p>Clique aqui para continuar para a <a href="https://muriloalvesdev.medium.com/proteja-suas-apis-rest-spring-boot-com-keycloak-parte-2-d741298ba211">parte 2</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d6a7fb225db4" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Proteja suas APIs REST Spring Boot com Keycloak — parte 2]]></title>
            <link>https://muriloalvesdev.medium.com/proteja-suas-apis-rest-spring-boot-com-keycloak-parte-2-d741298ba211?source=rss-4f6cc8a554a9------2</link>
            <guid isPermaLink="false">https://medium.com/p/d741298ba211</guid>
            <category><![CDATA[spring-security]]></category>
            <category><![CDATA[spring-web]]></category>
            <category><![CDATA[spring-boot]]></category>
            <category><![CDATA[authentication]]></category>
            <category><![CDATA[keycloak]]></category>
            <dc:creator><![CDATA[Murilo Alves]]></dc:creator>
            <pubDate>Thu, 10 Jun 2021 23:54:24 GMT</pubDate>
            <atom:updated>2021-06-11T15:16:49.162Z</atom:updated>
            <content:encoded><![CDATA[<h3>Proteja suas APIs REST Spring Boot com Keycloak — parte 2</h3><p>Construindo uma aplicação Spring Boot e configurando com Keycloak Spring Boot Adapter.</p><ul><li>Certifique-se de que o <a href="https://maven.apache.org/"><strong>Maven</strong></a> esteja instalado e configurado.</li><li>Vamos gerar o projeto utilizando a IDE <a href="https://spring.io/tools">Spring Tools 4</a></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/559/1*Y2zyt9cnARA2g2ue_ZkQmQ.png" /></figure><ul><li>Você também pode gerar o projeto utilizando o <a href="https://start.spring.io/">Spring Initializr</a></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/351/1*tBMqv4V2lAFH-qL3D4PW9g.png" /></figure><h3>Criando aplicação Spring Boot</h3><p>Utilizando Spring Tools vá em <strong>File -&gt; New -&gt; Spring Starter Project</strong>.</p><p>Preencha os campos da seguinte forma:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/795/1*QUh66HzrjzkyQQrBmXQ6Lg.png" /></figure><p>Clique em <strong>Next</strong>, e adicione as seguintes dependências,</p><ul><li>Spring Web</li><li>Spring Security</li><li>Spring Boot DevTools</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/561/1*ZOKYsuXVGkk3-y2P4996lw.png" /></figure><h3>Alguns detalhes no POM.xml</h3><ol><li>Adicione a propriedade de versão do <strong>Keycloak</strong></li></ol><ul><li>Encontre a seção &lt;properties&gt; e adicione a propriedade &lt;keycloak.version&gt;</li><li>Os valores das propriedades devem corresponder à versão do <strong>Keycloak</strong>. Se você instalou o Keycloak a partir deste artigo, utilize a versão <strong>13.0.1</strong>.</li></ul><p>Exemplo:</p><pre>&lt;properties&gt;<br>  &lt;java.version&gt;11&lt;/java.version&gt;<br>  &lt;keycloak.version&gt;13.0.1&lt;/keycloak.version&gt;<br>&lt;/properties&gt;</pre><p>2. Adicione a dependência do Keycloak</p><pre>&lt;dependency&gt;<br>   &lt;groupId&gt;org.keycloak&lt;/groupId&gt;<br>   &lt;artifactId&gt;keycloak-spring-boot-starter&lt;/artifactId&gt;<br>   &lt;version&gt;13.0.1&lt;/version&gt;<br>&lt;/dependency&gt;</pre><p>3. Adicione gerenciamento de dependências, abaixo da tag &lt;dependencies&gt;</p><pre>&lt;dependencyManagement&gt;<br>  &lt;dependencies&gt;<br>   &lt;dependency&gt;<br>    &lt;groupId&gt;org.keycloak.bom&lt;/groupId&gt;<br>    &lt;artifactId&gt;keycloak-adapter-bom&lt;/artifactId&gt;<br>    &lt;version&gt;${keycloak.version}&lt;/version&gt;<br>    &lt;type&gt;pom&lt;/type&gt;<br>    &lt;scope&gt;import&lt;/scope&gt;<br>   &lt;/dependency&gt;<br>  &lt;/dependencies&gt;<br>&lt;/dependencyManagement&gt;</pre><h3>Alguns detalhes no <strong>application.properties</strong></h3><p>Abra o arquivo <strong>application.properties</strong> em s<strong>rc/main/ esources</strong> e adicione as configurações Keycloak necessárias,</p><pre>server.port                         = 8000</pre><pre>keycloak.realm                      = &lt;REALM_NAME&gt;<br>keycloak.auth-server-url            = &lt;KEYCLOAK_SERVER_URL&gt;/auth<br>keycloak.ssl-required               = external<br>keycloak.resource                   = &lt;CLIENT_ID&gt;<br>keycloak.credentials.secret         = &lt;CLIENT_SECRET&gt;<br>keycloak.use-resource-role-mappings = true<br>keycloak.bearer-only                = true</pre><p>Exemplo:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/688/1*IOjXdPNKKuJrVYKma2X2Zg.png" /></figure><h3>Classe de configuração Java — KeycloakSecurityConfig.java</h3><p>O Keycloak fornece um <strong>KeycloakWebSecurityConfigurerAdapter</strong> como uma classe base conveniente para a criação de uma instância <strong>WebSecurityConfigurer</strong>. A implementação permite personalização por meio de métodos de substituição. Embora seu uso não seja obrigatório, ele simplifica muito a configuração do contexto de segurança.</p><p>Vamos criar <strong>KeycloakSecurityConfig.java</strong> no package config,</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/432/1*mTs6JQ1KSeqn1lqeloucug.png" /></figure><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8df69b53b356107ba97e463c3fc6f5ae/href">https://medium.com/media/8df69b53b356107ba97e463c3fc6f5ae/href</a></iframe><ul><li>Métodos<br><em>- </em>configureGlobal<em>()</em><strong><br> </strong>Registra o <strong>KeycloakAuthenticationProvider</strong> com o gerenciador de autenticação</li><li>- sessionAuthenticationStrategy()<br> Define a <strong>estratégia de autenticação</strong> da sessão.</li><li>- KeycloakConfigResolver<br> Por padrão, o Spring Security Adapter procura um arquivo keycloak.json de configuração.</li></ul><p>A propriedade <strong>jsr250Enabled</strong> nos permite usar a anotação <strong>@RoleAllowed</strong> . Exploraremos mais sobre essa anotação na próxima etapa.</p><h3>Classe de teste Java — TestController.java</h3><p>Precisamos de algumas APIs fictícias para testar a segurança da API.</p><p>Crie a classe <strong>TestController.java</strong> no package controller.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/455/1*aU_s1x9QThWUSZU1FYZ2Kw.png" /></figure><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/eeb4140d5b2133cf5113b38529346e09/href">https://medium.com/media/eeb4140d5b2133cf5113b38529346e09/href</a></iframe><h3>Execute a aplicação Spring Boot</h3><p>Você pode executar a aplicação através de seu <strong>terminal</strong> ou através da <strong>IDE Spring Tool</strong>.</p><p>1.<strong> Terminal </strong>utilizando o comando:</p><p>mvn spring-boot: run</p><p>2. <strong>IDE Spring Tool</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/545/1*2N9w_yDZb7tEe_Y0HgDMQg.png" /></figure><p><strong>Log da aplicação em execução:</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/528/1*tbJs-13uGjBvAVCzK9Rb1A.png" /></figure><h3>Request nas APIs</h3><p>Agora vamos realizar a chamada das nossas APIs REST utilizando <strong>CURL</strong> no terminal,</p><pre>curl -X GET &#39;<a href="http://localhost:8000/test/anonymous&#39;">http://localhost:8000/test/anonymous&#39;</a></pre><pre>curl -X GET &#39;<a href="http://localhost:8000/test/user&#39;">http://localhost:8000/test/user&#39;</a></pre><pre>curl -X GET &#39;<a href="http://localhost:8000/test/admin&#39;">http://localhost:8000/test/admin&#39;</a></pre><pre>curl -X GET &#39;<a href="http://localhost:8000/test/all-user&#39;">http://localhost:8000/test/all-user&#39;</a></pre><p>Response dos requests,</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/556/1*0DVs4Ey9dQCePJfWYv0l4Q.png" /></figure><p>Como pudemos ver, todas as APIs não requerem autenticação ou autorização. Agora, vamos tentar proteger esses endpoints da API.</p><h3>Definindo o acesso baseado em Role com a anotação @RolesAllowed</h3><h4>Endpoints</h4><p><strong><em>/test/user:</em><br></strong>Esta API deve ser acessível aos usuários com <em>demo-springboot-with-keycloak</em> com a role app-user. Isso pode ser definido apenas adicionando a anotação @RolesAllowed passando o parâmetro “user”, assim,</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/db78be21c1569fb67fd004bbcf66744a/href">https://medium.com/media/db78be21c1569fb67fd004bbcf66744a/href</a></iframe><p><strong><em>/test/admin:<br></em></strong>Esta API deve ser acessível aos usuários com <em>demo-springboot-with-keycloak</em> a role app-admin. Isso pode ser definido apenas adicionando a anotação @RolesAllowed passando o parâmetro “admin”, assim,</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5015b3bd3850159a4863e880e1d69a9f/href">https://medium.com/media/5015b3bd3850159a4863e880e1d69a9f/href</a></iframe><p><strong><em>/test/all-user:</em></strong><br>Esta API deve ser acessível aos usuários com <em>demo-springboot-with-keycloak</em> com as roles app-user e app-admin. Isso pode ser definido apenas adicionando a anotação @RolesAllowed passando os parâmetros “user” e “admin”, assim,</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/cd1830525a31d02f162b151467217b8a/href">https://medium.com/media/cd1830525a31d02f162b151467217b8a/href</a></iframe><p><strong><em>/test/anonymous:</em></strong><em><br></em>Esta API deve ser acessível sem qualquer token de autorização, sem restrições. Ele já atende aos nossos requisitos e não precisa de alterações adicionais.</p><p><strong>Classe TestController.java atualizada,</strong></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/7e0dfea1d7a0f7d843433f6ea99ddd76/href">https://medium.com/media/7e0dfea1d7a0f7d843433f6ea99ddd76/href</a></iframe><p>Execute a aplicação novamente para expor os endpoints com a autenticação adicionada.</p><h3>Testando Endpoints com autenticação</h3><ol><li>Endpoint <em>/test/user</em> requer um usuário com a <strong>role app-user</strong>, o usuário <strong>funcionario1</strong> contém esta role, sendo assim, <strong>vamos realizar uma nova requisição para capturarmos os access_token </strong>do funcionario1,</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*qVlxG54u5kp8chEJCUQxzA.png" /></figure><p>Copie o <strong>access_token</strong> e adicione em <strong>uma nova requisição</strong> no campo <strong>Authorizarion</strong> com o tipo <strong>Bearer Token</strong>,</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Jsr25dCttDmk9xvz7cMIpw.png" /></figure><p>Após adicionar o Token realize uma requisição no Endpoint <em>/test/user</em></p><p>Response,</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*s_7M8sno84PUCsSvYZbo7Q.png" /></figure><p>Sucesso!</p><p>Realizando request no endpoint <em>/test/admin</em> para validar que este usuário <strong>não tem permissão para consultar o endpoint</strong> <em>/test/admin</em> <strong>por ter somente a role que permite realizar requests no endpoint </strong><em>test/user</em>,</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_1qhTkEzT66S-ruBmIBCjg.png" /></figure><p><em>“Acesso negado”, status </em><a href="https://developer.mozilla.org/pt-BR/docs/Web/HTTP/Status/403"><em>HTTP 403</em></a><em>. Correto!</em></p><p>2. Endpoint <em>/test/admin</em> requer um usuário com a <strong>role app-admin</strong>, o usuário <strong>funcionario2</strong> contém esta role, sendo assim, <strong>vamos realizar uma nova requisição para capturarmos os access_token </strong>do funcionario2,</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*sLBRJttK8Y7cdJXnX6EUWw.png" /></figure><p>Request na API <em>/test/admin</em> passando o token,</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*qxQaKYiDwfwXcKSRHG5F7g.png" /></figure><p>Obtivemos sucesso nesta requisição também.</p><p>Realizando request no endpoint <em>/test/user</em> para validar que este usuário <strong>não tem permissão para consultar o endpoint</strong> <em>/test/user</em> <strong>por ter somente a role que permite realizar requests no endpoint </strong><em>test/admin</em>,</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*EhCn_zw9b2yfJSbleimYtg.png" /></figure><p><em>“Acesso negado”, status </em><a href="https://developer.mozilla.org/pt-BR/docs/Web/HTTP/Status/403"><em>HTTP 403</em></a><em>. Correto!</em></p><p>3. Realize o request para obter o <strong>access_token</strong> do <strong>funcionario3</strong> que, por sua vez, <strong>contém as roles</strong> <strong><em>app-admin </em>e<em> app-user</em></strong>. <strong>Este usuário deve conseguir realizar uma requisição em ambos os Endpoints e obter sucesso.</strong></p><p>Request no endpoint <strong>/test/user</strong> com o usuário <strong>funcionario3</strong>,</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mGQde-DBqWHaBhkCZNY9gQ.png" /></figure><p>Request no endpoint <em>/test/admin </em>com o usuário <strong>funcionario3</strong>,</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*a2OxQtV7n-r4Fqg6gkc1kA.png" /></figure><p>Todos os endpoints estão com autenticação adicionada.</p><h3>Removendo anotação <a href="http://twitter.com/RolesAllowed">@RolesAllowed</a> e adicionando complemento no método configure() da classe de configuração.</h3><p>Nossa classe de configuração <strong>KeycloakSecurityConfig.java</strong> contém um método chamado <strong>configure()</strong> e o mesmo está permitindo qualquer requisição, por isso a necessidade de adicionarmos a anotação. Mostrei como adicionar as roles através da anotação inicialmente porque achei interessante mostrar que também existe essa possibilidade.</p><p>Basicamente basta sobrescrever seu método configure, disso:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/27d3a46ec050f52b3ecf2059312c5a13/href">https://medium.com/media/27d3a46ec050f52b3ecf2059312c5a13/href</a></iframe><p>Para isso:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/41aa41e718d833ab05242f8f0221c021/href">https://medium.com/media/41aa41e718d833ab05242f8f0221c021/href</a></iframe><h3>FIM!</h3><p>Caso tenha interesse em consultar o projeto no github, <a href="https://github.com/muriloalvesdev/demo-springboot-with-keycloak">clique aqui</a>.</p><h3>REFERÊNCIAS</h3><ul><li><a href="https://jwt.io/">JSON Web Tokens - jwt.io</a></li><li><a href="https://blog.db1group.com/o-que-e-keycloak/">O que é Keycloak e como começar a usar - Blog DB1</a></li><li><a href="https://help.blackboard.com/pt-br/Learn/Administrator/SaaS/Authentication/Implement_Authentication/LDAP_Authentication_Provider_Type#:~:text=LDAP%20(Lightweight%20Directory%20Access%20Protocol,informa%C3%A7%C3%B5es%20e%20recuperar%20as%20informa%C3%A7%C3%B5es.">Tipo de provedor de autenticação LDAP</a></li><li><a href="https://en.wikipedia.org/wiki/Single_sign-on">Single sign-on - Wikipedia</a></li><li><a href="https://pt.wikipedia.org/wiki/OpenID">OpenID - Wikipédia, a enciclopédia livre</a></li><li><a href="https://imasters.com.br/desenvolvimento/como-funciona-o-protocolo-oauth-2-0">Como funciona o protocolo OAuth 2.0 - iMasters - We are Developers</a></li><li><a href="https://en.wikipedia.org/wiki/Security_Assertion_Markup_Language">Security Assertion Markup Language - Wikipedia</a></li><li><a href="https://www.keycloak.org/getting-started/getting-started-docker">Docker</a></li><li><a href="https://curl.se/docs/manpage.html">curl - How To Use</a></li><li><a href="https://spring.io/tools">Tools</a></li><li><a href="https://developer.mozilla.org/pt-BR/docs/Web/HTTP/Status/401">401 Unauthorized - HTTP | MDN</a></li><li><a href="https://developer.mozilla.org/pt-BR/docs/Web/HTTP/Status/403">403 Forbidden - HTTP | MDN</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d741298ba211" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Removendo valores nulos em listas — Java]]></title>
            <link>https://muriloalvesdev.medium.com/removendo-valores-nulos-em-listas-java-b542cef96db9?source=rss-4f6cc8a554a9------2</link>
            <guid isPermaLink="false">https://medium.com/p/b542cef96db9</guid>
            <category><![CDATA[lambda]]></category>
            <category><![CDATA[guava]]></category>
            <category><![CDATA[java]]></category>
            <category><![CDATA[collections-framework]]></category>
            <category><![CDATA[lambda-function]]></category>
            <dc:creator><![CDATA[Murilo Alves]]></dc:creator>
            <pubDate>Wed, 18 Nov 2020 19:57:45 GMT</pubDate>
            <atom:updated>2020-11-19T01:18:18.160Z</atom:updated>
            <content:encoded><![CDATA[<h3>Removendo valores nulos em listas — Java</h3><p>Neste pequeno tópico vou mostrar como remover todos os elementos nulos de uma lista. Usando Java simples, <a href="https://github.com/google/guava">Guava</a>, as coleções Apache Commons e o suporte a lambda Java 8 mais recente.</p><h4>Opção 1:</h4><h4>Removendo valores nulos de uma lista usando o Java simples.</h4><p>Um loop while básico :</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/570658d07956422ce5345044e621999a/href">https://medium.com/media/570658d07956422ce5345044e621999a/href</a></iframe><p>Como outra alternativa, também podemos chegar no mesmo resultado:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d22620146e77d0bb23b36eaef58cd861/href">https://medium.com/media/d22620146e77d0bb23b36eaef58cd861/href</a></iframe><p>Observe que ambas as soluções modificaram a lista de fontes.</p><h4>Opção 2:</h4><h4>Removendo valores nulos de uma lista usando o <a href="https://github.com/google/guava">Google Guava</a>.</h4><p>Também podemos remover nulos usando <a href="https://github.com/google/guava">Guava</a>, por meio de predicados:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a3933a010bfae13226abe23704429b05/href">https://medium.com/media/a3933a010bfae13226abe23704429b05/href</a></iframe><p>Como alternativa, se não quisermos modificar a lista, o <a href="https://github.com/google/guava">Guava</a> nos permite criar uma nova lista de filtros:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0cb8e016831c30394f82a8ec0f7a9ac9/href">https://medium.com/media/0cb8e016831c30394f82a8ec0f7a9ac9/href</a></iframe><h4>Opção 3:</h4><h4>Removendo valores nulos de uma lista usando <a href="https://commons.apache.org/proper/commons-collections/">Apache Commons Collections</a>.</h4><p>Vejamos agora uma solução simples usando a biblioteca <a href="https://commons.apache.org/proper/commons-collections/">Apache Commons Collections</a>:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8651e18e83eeaf03fa7fac0a82e1a1c2/href">https://medium.com/media/8651e18e83eeaf03fa7fac0a82e1a1c2/href</a></iframe><h4>Opção 4:</h4><h4>Removendo valores nulos de uma lista usando <a href="https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html">Lambda (Java 8)</a></h4><p>Vamos olhar agora para uma solução Java 8 usando Lambdas para filtrar a Lista ; o processo de filtragem pode ser feito em paralelo ou serial:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2cea14b74df66313f7f3e064c55cc872/href">https://medium.com/media/2cea14b74df66313f7f3e064c55cc872/href</a></iframe><p>Espero ter ajudado com algumas soluções rápidas e muito úteis para se livrar de todos os valores nulos de uma Lista.</p><h4>Conclusão</h4><p>Neste tópico, exploramos diferentes abordagens que podemos ter para remover nulos de uma lista usando Java simples, Guava ou Lambdas.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b542cef96db9" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[JUnit5 — Definindo a ordem de execução de testes]]></title>
            <link>https://muriloalvesdev.medium.com/junit5-definindo-a-ordem-de-execu%C3%A7%C3%A3o-de-testes-d279b15c1a11?source=rss-4f6cc8a554a9------2</link>
            <guid isPermaLink="false">https://medium.com/p/d279b15c1a11</guid>
            <category><![CDATA[junit-5]]></category>
            <category><![CDATA[test-driven-development]]></category>
            <category><![CDATA[spring]]></category>
            <category><![CDATA[test]]></category>
            <dc:creator><![CDATA[Murilo Alves]]></dc:creator>
            <pubDate>Wed, 09 Sep 2020 02:35:39 GMT</pubDate>
            <atom:updated>2021-05-12T17:08:47.757Z</atom:updated>
            <content:encoded><![CDATA[<h3>JUnit5 — Definindo a ordem de execução de testes</h3><p>Neste tópico vou abordar como podemos definir qual a ordem de execução de nossos testes utilizando <a href="https://junit.org/junit5/">JUnit5</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/881/0*KCWnsZKN7om4ubFz.jpeg" /></figure><p>Vamos iniciar com um <em>test case</em>.</p><h4>Dado que</h4><p>Precisamos criar <a href="https://pt.wikipedia.org/wiki/Teste_de_integra%C3%A7%C3%A3o">testes de integração</a> para uma aplicação simples que realiza um <a href="https://pt.wikipedia.org/wiki/CRUD">CRUD</a>.</p><h4>Ordem de execução</h4><p>Para que o teste integrado da <a href="https://pt.wikipedia.org/wiki/Interface_de_programa%C3%A7%C3%A3o_de_aplica%C3%A7%C3%B5es">API</a> responsável por receber uma requisição para DELETAR um objeto seja um teste efetivo, precisamos primeiramente ter um objeto salvo no nosso banco de dados, ou seja, o teste de requisição na API responsável por SALVAR um objeto deve ser executado primeiro.</p><p>Particularmente encontrei vários exemplos como este aqui na internet:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8fb9f3cf566d2cd156c0c0f2976d13f4/href">https://medium.com/media/8fb9f3cf566d2cd156c0c0f2976d13f4/href</a></iframe><p>Perceba que antes de iniciar a execução dos testes, o método <em>setUp()</em> está realizando uma requisição para popular a base antes de efetuar o DELETE, mas após rodar a classe de teste o que teremos como teste real será apenas o método<em> shouldDeleteObject()</em> e sabemos que isso não é o que queremos.</p><h4>Executando testes na ordem desejada</h4><p>O JUnit5 desenvolveu uma anotação chamada <a href="https://junit.org/junit5/docs/5.4.0-RC1/api/org/junit/jupiter/api/Order.html#value()">@Order</a> que recebe como parâmetro um número inteiro, de acordo com a <a href="https://junit.org/junit5/docs/5.4.0-RC1/api/org/junit/jupiter/api/Order.html#value()">documentação</a>:<br>“<em>Os elementos são ordenados com base na prioridade, onde um valor inferior tem maior prioridade do que um valor superior. Por exemplo, Integer.</em><strong><em>MAX_VALUE</em></strong><em> tem a prioridade mais baixa.</em>”</p><p>Ou seja, se tivermos um método anotado com <em>@Order(1)</em> o mesmo deve ser executado primeiro, sendo assim, podemos alterar o nome do método <em>setUp()</em> para <em>shouldPersistObject()</em> para que ele tenha um nome que de fato descreva qual a sua verdadeira responsabilidade e por fim bastaria anotarmos os dois métodos da seguinte maneira:</p><blockquote><em>PS: Adicione a seguinte anotação em sua classe de testes</em> @TestMethodOrder(MethodOrderer.OrderAnnotation.class)</blockquote><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/22b43ebca67498a43c9454e15be3a8c1/href">https://medium.com/media/22b43ebca67498a43c9454e15be3a8c1/href</a></iframe><p>Agora temos de fato, dois testes. O primeiro teste a ser executado será o método <em>shouldPersistObject()</em>, onde sua responsabilidade é enviar uma requisição que resultará na persistência de um objeto. O teste <em>shouldDeleteObject()</em> será executado logo após a conclusão do primeiro.</p><p>Espero que esta informação seja útil para você como foi para mim!</p><h4>Referência</h4><p><a href="https://junit.org/junit5/docs/5.4.0-RC1/api/org/junit/jupiter/api/Order.html">Order (JUnit 5.4.0-RC1 API)</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d279b15c1a11" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Consumindo a API Postmon gratuita utilizando oRestTemplate e Spring Boot]]></title>
            <link>https://muriloalvesdev.medium.com/consumindo-a-api-postmon-gratuita-utilizando-oresttemplate-e-spring-boot-670fe6ceb86f?source=rss-4f6cc8a554a9------2</link>
            <guid isPermaLink="false">https://medium.com/p/670fe6ceb86f</guid>
            <dc:creator><![CDATA[Murilo Alves]]></dc:creator>
            <pubDate>Tue, 18 Feb 2020 15:27:36 GMT</pubDate>
            <atom:updated>2024-04-24T16:23:20.101Z</atom:updated>
            <content:encoded><![CDATA[<h3>Consumindo a API Postmon com RestTemplate e Spring Boot + Teste de integração com JUnit</h3><p>A API Postmon é baseada em REST, basta fazermos uma chamada para a url abaixo: <br><em>https://api.postmon.com.br/v1/cep/*cep_a_consultar*</em></p><p>Antes de começarmos a exibir códigos e falarmos algumas palavras &quot;difíceis&quot;, vamos começar entendendo o que seria REST e o que seria essa &quot;chamada&quot;.</p><h3>REST, o que seria?</h3><p>A <strong>Representational State Transfer</strong> (REST), em português Transferência de Estado Representacional, é uma abstração da arquitetura da World Wide Web, mais precisamente, é um estilo arquitetural que consiste de um conjunto coordenado de restrições arquiteturais aplicadas a componentes, conectores e elementos de dados dentro de um sistema de hipermídia distribuído.</p><p>O REST ignora os detalhes da implementação de componente e a sintaxe de protocolo com o objetivo de focar nos papéis dos componentes, nas restrições sobre sua interação com outros componentes e na sua interpretação de elementos de dados significantes.</p><p>Ele foi definido oficialmente pela <a href="http://www.w3.org/">W3C</a>.<br>Fonte: <a href="http://pt.wikipedia.org/wiki/REST">Wikipedia</a> (<a href="http://en.wikipedia.org/wiki/Representational_state_transfer">em inglês</a>)</p><p>Ele é frequentemente aplicado à <em>web services</em> fornecendo APIs para acesso a um serviço qualquer na web. Ele usa integralmente as mensagens HTTP para se comunicar através do que já é definido no protocolo sem precisar &quot;inventar&quot; novos protocolos específicos para aquela aplicação.</p><p>Você trabalha essencialmente com componentes, conectores e dados.</p><ul><li>Ele usa o protocolo HTTP (verbos, <em>accept headers</em>, códigos de estado HTTP, <em>Content-Type</em>) de forma explícita e representativa para se comunicar. URIs são usados para expor a estrutura do serviço. Utiliza uma notação comum para transferência de dados como XML ou JSON.</li></ul><p>No caso da API Postmon a transferência dos dados é em formato JSON e a &quot;chamada&quot; é feita utilizando o verbo HTTP GET.</p><h3>FAZENDO A CHAMADA MANUALMENTE</h3><p>Copie e cole a URI abaixo em seu navegador:<br>[https://api.postmon.com.br/v1/cep/adicione_seu_cep_aqui]</p><p>Você terá uma resposta semelhante a imagem abaixo:</p><figure><img alt="Resposta da chamada da API" src="https://cdn-images-1.medium.com/max/666/1*feL9XwR7AWtTubDG8sHjVw.png" /><figcaption>Resposta da chamada utilizando o CEP 40020160</figcaption></figure><h3>O RestTemplate</h3><p>Não vamos entrar em detalhes sobre como funciona o RestTemplate, já que o foco aqui é consumir a API Postmon. Mas vale adicionar uma frase da documentação, rs.</p><p><a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html"><em>The RestTemplate offers templates for common scenarios by HTTP method, in addition to the generalized </em></a><a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html"><em>exchange and </em></a><a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html"><em>execute methods that support of less frequent cases.</em></a></p><p>Já que a classe está pronta e consegue executar exatamente o que precisamos para consumirmos a API Postmon, bora por a mão na massa!</p><h3>CRIANDO PROJETO SPRING BOOT</h3><p><a href="https://start.spring.io/">Crie seu projeto Spring Boot</a>, dê o seguinte nome para o projeto <em>ConsumerApiPostmon</em> e siga o passo-a-passo abaixo:</p><p>Agora que sabemos como é a resposta da API Postmon precisamos mapear isso em nossa aplicação (que acabamos de criar). Para que o conteúdo deste artigo fique sincronizado com o projeto que você criou, deixe seus pacotes no formato <em>br.com.postmon</em>.</p><p>Seu projeto deve estar assim:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/616/1*hyR_DCSjMGDWxbQt3zSIFQ.png" /><figcaption>Hierarquia de pacotes contendo a classe principal de sua aplicação Spring Boot</figcaption></figure><h3>ENTENDENDO NOSSO MODELO</h3><p>De acordo com a resposta da API Postmon temos 3 objetos dentro do JSON:</p><p>1 Objeto principal contendo todas as informações agrupadas;</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/666/1*feL9XwR7AWtTubDG8sHjVw.png" /><figcaption>Esta é a mesma imagem da primeira requisição que fizemos anteriormente, observe que todo o conteúdo está dentro de { este é o objeto principal agrupando todo o conteúdo }</figcaption></figure><p>1 Objeto com algumas informações da cidade;</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/614/1*bvZErYjbWTdd4LOY2wrt5A.png" /><figcaption>Objeto &quot;cidade_info&quot; que contém 2 atributos</figcaption></figure><p>1 Objeto com algumas informações do estado;</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/624/1*u6irad_SWSrkkPSPrIKgkw.png" /><figcaption>Objeto &quot;estado_info&quot; que contém 3 atributos</figcaption></figure><h3>CRIANDO NOSSOS MODELOS</h3><p><em>Todos os modelos devem ficar dentro do pacote br.com.postmon.model</em></p><p>Para conseguirmos consumir a API precisamos criar 3 classes modelos que representam esses 3 objetos contidos na resposta da requisição.</p><p>Crie uma classe com o nome <em>CityInfo</em> para representar o objeto &quot;cidade_info&quot; do JSON e adicione 3 atributos do tipo String, como os atributos do JSON estão com <em>Underline ( _ )</em>, e não é uma boa prática adicionar isso em nomenclatura de variáveis ou classes vamos utilizar uma anotação chamada <em>@JsonProperty</em> passando entre parênteses o valor do atributo contido no JSON.</p><p><a href="https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations"><strong>Link da dependência @JsonProperty</strong></a></p><p>Abaixo temos um exemplo de como a classe <em>CityInfo</em> deve ficar:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*y5gvV7Cro_i7iK2q5sc90A.png" /><figcaption>Classe CityInfo</figcaption></figure><p>Faremos o mesmo com a classe que deve representar o objeto &quot;estado_info&quot;:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/994/1*9CHPSh2F6MMQlmc3cI8HZQ.png" /><figcaption>Classe StateInfo</figcaption></figure><p>E por fim, nosso último objeto que contém todas as informações agrupadas:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1014/1*J9yb7jSlAMge1dDDL1VIOQ.png" /><figcaption>Classe Address</figcaption></figure><p>Perceba que nosso objeto <em>Address</em> contém 2 objetos como atributo, o <em>CityInfo</em> e também o <em>StateInfo</em>, ambos estão anotados com @JsonProperty(&quot;nome_que_o_mesmo_representa_dentro_do_json&quot;).</p><p>Agora, seus pacotes e classes devem estar assim:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/606/1*MbzwaJW-cIMG_2DeOMetCQ.png" /><figcaption>Hierarquia de pacotes contendo a classe principal de sua aplicação Spring Boot e os modelos que acabamos de criar</figcaption></figure><h3>CONSUMINDO A API POSTMON</h3><p>Agora que mapeamos o JSON e sabemos que a classe RestTemplate é capaz de realizar requisições HTTP, vamos consumir a API Postmon e popular nossos objetos com a resposta.</p><p>Crie sua classe de serviço que deverá ficar dentro do pacote <em>br.com.postmon.service</em> com o seguinte nome, <em>ConsumerApiPostmonService</em></p><p>Anote sua classe com a anotação <em>@Service</em> do próprio Spring.</p><p>Vamos bem devagar para que você não fique perdido(a). <br>Seu serviço deve estar assim até o momento:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/938/1*Ziz5X-kP7MHkkyFyglPMGg.png" /><figcaption>Classe ConsumerApiPostmonService apenas com sua anotação @Service</figcaption></figure><h4>URL BASE</h4><p>Sabemos que para realizar uma chamada na API Postmon é necessário ter a URL BASE que é [ https://api.postmon.com.br/v1/cep/ ].</p><p>Exemplo do que é uma URL BASE:</p><p>Se um sistema conter várias APIs para realizar um <em>CRUD</em> de um usuário:<br><em>/save<br>/update<br>/delete<br>/find</em></p><p>A URL BASE das APIs acima poderia ser<em> http://crud.com.br/</em> e consequentemente após a <em>br/ </em>seria o<em> /save /update /delete</em> e por fim <em>/find</em> .</p><p>Em uma URL, o nome do que vem depois da URL BASE, por exemplo, <em>/save</em> é chamado de <strong>endereço de caminho</strong>. A URL BASE nunca muda, ou seja, sempre vamos precisar da seguinte URL:<br>[https://api.postmon.com.br/v1/cep/] para consumir a API Postmon.</p><p>Quando costumo criar requisições em sistemas externos, gosto de adicionar essas URLs base como <a href="https://blog.indrek.io/articles/using-environment-variables-with-spring-boot/">variáveis de ambiente</a>.</p><h4>Variável de ambiente</h4><p>Basicamente basta adicionarmos uma variável dentro do nosso arquivo <em>application.properties</em> e adicionar um valor a ela (o valor será a URL BASE da API Postmon).</p><p>O arquivo <em>application.properties</em> fica dentro do diretório <em>src/main/resources</em> de sua aplicação conforme a representação da imagem abaixo:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/366/1*y-iV_X03shA41r9btDAomw.png" /><figcaption>arquivo application.properties de nossa aplicação</figcaption></figure><p>Abra o arquivo adicione o seguinte texto:<br><em>url.postmon=https://api.postmon.com.br/v1/cep/<br></em><strong><em>url.postmon</em> </strong>é a nossa variável <strong>e o valor dela é a URL BASE</strong></p><p>Seu arquivo deve ficar assim:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/938/1*o0Tni5Jctpc0xjFwcA7_Ag.png" /><figcaption>variável de ambiente adicionada no arquivo application.properties</figcaption></figure><p>Agora que já adicionamos a URL BASE como variável de ambiente, só precisamos adicionar a anotação <em>@Value(&quot;${nome_variável_de_ambiente}&quot;) </em>em uma variável no nosso serviço, assim o Spring consegue atribuir a uma variável o valor da URL BASE que está dentro do arquivo <em>application.properties</em>.</p><p>Após adicionar a variável seu serviço:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mFCFbgxQ8st9R73YNejPPw.png" /><figcaption>variável de ambiente adicionada em nossa classe de serviço</figcaption></figure><p>Como nosso serviço deve receber um CEP para concatenar com a URL BASE, precisamos criar um método que deve receber um CEP e consequentemente concatena o CEP com o atributo URL e assim montar nossa URL completa.</p><p>Seu método deve ficar assim:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zM9_wtSSuO-Op7vpGdLCqw.png" /><figcaption>método consumer responsável por concatenar o CEP recebido com a URL BASE e consumir a API Postmon</figcaption></figure><h4>Enfim, o RestTemplate!</h4><p>Crie uma instancia do RestTemplate utilizando o comando <strong>new</strong>. Ou seja, new RestTemplate(); <br>Crie também uma variável de referência desta instancia:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1014/1*XvMj4TD1XyoondoBn7Xzpw.png" /><figcaption>Instanciando o RestTemplate</figcaption></figure><p>Conforme a <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html">documentação do RestTemplate</a> existe um método nesta classe chamado <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html#getForObject-java.net.URI-java.lang.Class-"><em>getForObject</em></a>. Ele é responsável por realizar uma requisição utilizando o verbo HTTP GET, após realizar arequisição na URL que passarmos para ele, o mesmo converte a resposta em objeto, no caso o que criamos [<em>Address, CityInfo e StateInfo</em>]. Incrível, não?</p><p>Vamos ver na prática como isso funciona:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*XnhZmV9E7mtCTFTkVch7zg.png" /><figcaption>Utilizando método getForObject do RestTemplate passando a URL completa e o objeto no qual o método getForObject deve receber através da requisição que será realizada</figcaption></figure><blockquote><em>Sintaxe: <br>getForObject(url_completa, objeto_esperado_na_resposta)</em></blockquote><p>Muito simples, não? <br>Vamos adicionar um retorno em nosso método para conseguirmos testar esta requisição, adicione a nossa classe Address como retorno:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*IJMhiEKFS685VcwbmgtkaA.png" /><figcaption>Método consumer concluído</figcaption></figure><h3>TESTE DE INTEGRAÇÃO DO SERVIÇO</h3><p>Vamos utilizar o <a href="https://junit.org/junit5/">JUnit</a> para testarmos nosso serviço.</p><p>Seu projeto contém um diretório chamado <em>src/test/java</em> com apenas 1 classe de teste. Vamos criar uma nova classe dentro do pacote <em>service</em> do diretório de teste com o nome do nosso serviço + a palavra <em>Test</em> na frente, ficará assim <em>ConsumerApiPostmonServiceTest:</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/642/1*kHg983V0q4I3kIAgvSQJkA.png" /><figcaption>Hierarquia de pacotes com a classe de teste do nosso serviço</figcaption></figure><p>A intenção deste teste é validar se a integração entre nosso serviço e a API Postmon está funcionando. Então vamos anotar nossa classe com:<br><em>@SpringBootTest<br>@RunWith(SpringRunner.</em><strong><em>class</em></strong><em>)</em></p><p>Vamos fazer a injeção do nosso serviço na classe de teste adicionando nosso serviço como atributo da classe e anotando o mesmo com @Autowired .</p><p>Classe de teste:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/936/1*ZlgsZGw89iSJSrYA-upHjg.png" /><figcaption>Classe de teste injetando o serviço que criamos</figcaption></figure><p>Crie o método responsável por testar o serviço, vamos chamá-lo de <em>consumerTest()</em>:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2SNvh7FSzMrpVs1udaTR9A.png" /><figcaption>Método consumerTest();</figcaption></figure><p>Vamos utilizar o mesmo CEP do início do artigo para realizar o teste, se quiser, adicione o CEP de sua preferência.<br>Utilize a variável de referência do nosso serviço que chamamos de <em>service</em> para chamar o método <em>consumer(informe_um_cep)</em> e atribua o retorno a uma variável de referência do tipo <em>Address</em>:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*N-zRkXvad0uLsqYAnwg4TQ.png" /><figcaption>Nosso teste recebendo a resposta</figcaption></figure><p>Como sabemos dentro do JSON de resposta temos 2 Objetos o <em>cidade_info</em> e o <em>estado_info</em>. Esses 2 objetos estão contidos como atributos dentro da nossa classe <em>Address</em>. Pegue os 2 atributos conforme a imagem abaixo:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1018/1*4_ycxPuNPi5lZPpr8YspVQ.png" /><figcaption>Nosso teste capturando os 3 objetos de retorno</figcaption></figure><p>Agora, vamos utilizar o método <a href="http://junit.sourceforge.net/javadoc/org/junit/Assert.html"><em>assertEquals</em></a> para validar se o que esperamos de resposta realmente é o que retornou da API Postmon.</p><blockquote><em>Sintaxe:<br></em><a href="http://junit.sourceforge.net/javadoc/org/junit/Assert.html"><em>assertEquals</em></a><em>(O que esperamos, O que retornou)</em></blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7B6k2ahLgTKKPFHBR9KNXQ.png" /><figcaption>Método de teste concluído</figcaption></figure><p>Para executarmos nosso teste, precisamos clicar com o lado direito do nosso mouse em cima do nome do método, ir até a opção <em>RunAs</em> e clicar em <em>JUnit Test</em>:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/590/1*-_56R0NgBOBrHM82z_0-5w.png" /><figcaption>JUnit Test</figcaption></figure><p>Após a execução, nosso teste ficará verde:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*u18Lnm5CQtJF_oeL6p5oCw.png" /><figcaption>Teste concluído</figcaption></figure><p>Nosso teste está verde porque o que esperávamos de resposta da API Postmon retornou, ou seja, nosso serviço consumiu a API Postmon e retornou com os dados que queríamos.</p><p>Caso você queira ver o retorno com os seus próprios olhos, adicione o método <em>toString()</em> dentro dos 3 objetos e adicione o <em>Address</em> dentro de um <em>sysout()</em>:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*J9N4kG5BClclT_4OuUtTzA.png" /><figcaption>Printando classe Address</figcaption></figure><blockquote>Resposta:<br><em>Address [neighborhood=Centro, city=Salvador, stateInfo=StateInfo [area=564.732,642, codeIBGE=29, name=Bahia], postalCode=40020160, cityInfo=CityInfo [area=692,819, codeIBGE=2927408], state=BA]</em></blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bU6pUN42IEW_jyu3tl6e4Q.png" /><figcaption>Console printando retorno da API Postmon</figcaption></figure><p>De acordo com o teste nossa aplicação está funcionando como esperado. Podemos concluir que consumir uma API externa é bem simples e objetiva quando utilizamos o <em>getForObject</em> do <em>RestTemplate</em>. <br>O intuito deste artigo é ajudar iniciantes que tem uma certa dificuldade para conseguir entender como funciona o consumo de uma API externa.</p><p>Espero ter ajudado.</p><h3>Referências:</h3><p><a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html#getForObject-java.net.URI-java.lang.Class-">https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html#getForObject-java.net.URI-java.lang.Class-</a></p><p><a href="https://blog.indrek.io/articles/using-environment-variables-with-spring-boot/">https://blog.indrek.io/articles/using-environment-variables-with-spring-boot/</a></p><p><a href="https://junit.org/junit5/">https://junit.org/junit5/</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=670fe6ceb86f" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Conectando METABASE ao ATHENA (AWS) utilizando Docker]]></title>
            <link>https://muriloalvesdev.medium.com/conectando-metabase-ao-athena-aws-utilizando-docker-8cef92980597?source=rss-4f6cc8a554a9------2</link>
            <guid isPermaLink="false">https://medium.com/p/8cef92980597</guid>
            <category><![CDATA[metabase]]></category>
            <category><![CDATA[aws-athena]]></category>
            <category><![CDATA[aws-glue]]></category>
            <category><![CDATA[amazon-s3]]></category>
            <category><![CDATA[docker]]></category>
            <dc:creator><![CDATA[Murilo Alves]]></dc:creator>
            <pubDate>Sat, 30 Nov 2019 13:50:23 GMT</pubDate>
            <atom:updated>2019-12-02T12:17:17.314Z</atom:updated>
            <content:encoded><![CDATA[<p>Bem, acredito que você assim como eu está procurando a algum tempo uma forma de conectar o Metabase ao Athena (aws). Como não encontrei nenhuma fonte em português, decidi criar este artigo para tentar ajudar a comunidade.</p><p>Vamos utilizar um Docker do metabase e conectar o mesmo ao Athena (AWS).</p><h4>Sem enrolação, vamos por a mão na massa!</h4><h3>Baixando imagem Docker do Metabase</h3><p>Precisamos de uma imagem Docker do metabase, para fazer download execute o comando $<a href="https://hub.docker.com/r/metabase/metabase">docker run -d -p 3000:3000 --name metabase metabase/metabase</a>.</p><p>Após efetuar o download, verifique se a imagem está up utilizando o comando $docker ps . Precisamos que seu terminal retorne algo parecido com a imagem abaixo:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cJssGTYYwo2mZY43yy__LA.png" /><figcaption>Se não aparecer isto após executar o comando, verifique novamente o primeiro passo para efetuar o download da imagem Docker corretamente.</figcaption></figure><p>Agora que sua imagem Docker está up abra seu navegador e digite <a href="http://localhost:3000/">http://localhost:3000</a> .</p><h3>Conta do administrador</h3><p>Agora você deve configurar seu usuário de acesso, aparecerá uma tela parecida com esta:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*CgqEN8SkAxTTDwhu.png" /><figcaption>Preencha todos os dados corretamente</figcaption></figure><h3>Configurando acesso ao banco de dados Athena</h3><p>Veja que em database type o Athena não está disponível como opção.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/650/1*CF1bfHmtlPIrvXvoWiqwww.png" /><figcaption>Abra as opção e veja que o Athena não está disponível como opção</figcaption></figure><p>Para conectar o Athena ao Metabase precisamos do Driver de conexão do Athena, os Drivers de conexões com os bancos de dados disponíveis atualmente (2019/11/30) são limitados e não temos por padrão a conexão com o Athena.</p><p>Depois de muita procura, encontrei este Driver: <a href="https://github.com/dacort/metabase-athena-driver/releases/tag/v0.0.3">https://github.com/dacort/metabase-athena-driver/releases/tag/v0.0.3</a></p><p>Faça download do driver, pois ele será o responsável por habilitar a conexão com o Athena.</p><p>Após efetuar o download, precisamos adicionar o jar dentro do diretório plugins/ do container Docker metabase . Fazer isso é bem simples, siga o passo a passo abaixo.</p><h4>Adicionando Driver do Athena no container Docker do Metabase</h4><p>Acesse seu container utilizando o comando docker exec -it (container_id) /bin/bash .</p><p>Liste os diretórios contidos em seu container utilizando o comando ls :</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*AhsFY2zZ-Ivui-8CIB9RbA.png" /><figcaption>Diretórios do container Docker (metabase)</figcaption></figure><p>Veja que o diretório plugins está ali!</p><p>Utilize o comando exit para sair do container.</p><p>Acessamos o container Docker para que vocês vejam que está tudo conforme esperávamos. Agora para que o Athena fique disponível precisamos copiar o jar para dentro do diretório plugins/ do container Docker.</p><p>Para executar esta ação, utilize o comando $ docker cp driver_athena.jar seu_container_id:/plugins/ .</p><p>Agora que adicionamos o Driver no diretório correto, reinicie seu container Docker utilizando o comando $docker restart seu_container_id .</p><p>Acesse novamente através do navegador o metabasehttp://localhost:3000 .</p><p>Agora voltando a configuração do seu banco de dados veja que em database type o Athena está disponível, aparecerá uma tela similar a esta após selecionar o Athena como database:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-5mHNWZbjE4sydoshgltlA.png" /><figcaption>Configuração do banco de dados</figcaption></figure><p>Você precisa ter os seguintes dados para se conectar ao banco de dados:</p><p><em>Em database type selecione o Athena que agora estará disponível;</em></p><p><em>Nome para o banco de dados;</em></p><p><em>Região em que o s3 (local onde o Athena estará consumindo) se localiza;</em></p><p><em>AccessKey: credenciais do usuário de acesso ao Bucket s3;</em></p><p><em>SecrectKey: credenciais privadas do usuário de acesso ao Bucket s3;</em></p><p>Se seu banco não for muito grande, pode deixar marcado apenas a opção <em>execute queries automaticamente ao filtrar ou sumarizar.</em></p><p>Clique em salvar e pronto, sua conexão com o banco de dados Athena estará concluída.</p><h3>Dica:</h3><p>Seu usuário de acesso (IAM na AWS) precisa ter as permissões abaixo, para que o Metabase consiga chegar ao Athena, catálogo de dados (tabela, AWSGlue) e ao AmazonS3.</p><p><em>AmazonS3FullAccess;</em></p><p><em>AmazonAthenaFullAccess;</em></p><p><em>AWSGlueConsoleFullAccess;</em></p><h3>Referências:</h3><ul><li><a href="https://hub.docker.com/r/metabase/metabase">Docker Hub</a></li><li><a href="https://www.metabase.com/docs/latest/">Metabase documentation</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8cef92980597" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>