Este artigo é para os programadores Ruby que buscam a possibilidade de substituir um pouco de Ruby e Rails por Elixir e Phoenix.
Indo direto ao ponto, muitas aplicações pequenas em Ruby que eu desenvolvi começam com dois add-ons simples: Devise, para autenticação e ActiveAdmin para gerenciamento básico de bancos de dados. Então eu começava daí.
Tanto o Elixir quanto o Phoenix estão mudando rápido, por isso, é difícil para um conjunto estável de bibliotecas se solidificar, mas eu acho que finalmente estamos saindo da curva dos early adopters.
Um grande ponto de contenção tem sido a autenticação de usuários. Muitos tradicionalistas vão dizer que você tem que criar o seu do zero ou utilizando bibliotecas de baixo nível, como o Guardian.
Se você estiver criando uma aplicação que somente exiba saídas de APIs, provavelmente está ok. Mas para uma aplicação web completa desenvolvida para utilização de humanos, essa dificilmente será uma boa escolha. Não vou entrar nessa discussão hoje, pois ela está fora do contexto.
Estou assumindo que você ao menos viu os tutoriais de Elixir e Phoenix. Se ainda não viu, vá em frente e leia, você vai levar 1 ou 2 dias para entender o básico, se você já for um desenvolvedor Ruby experiente. Depois volte e leia meus artigos sobre Elixir para entender como ele é em comparação aos outros.
Tendo dito isso, vamos começar.
Coherence (Alternativa para o Devise)
Finalmente, eu encontrei esse projeto que esteve em um desenvolvimento pesado pelos últimos 6 meses chamado Coherence. Para todos os propósitos, ele imita o Devise em quase tudo. E isso é muito bom para muitos cenários.
Seu README é bem explicado o suficiente, então não vou copiar e colar ele aqui, basta ler e começar a utilizar. Mas se você quiser testar todas suas funcionalidades, você pode ajustar seus procedimentos com essas opções durante a instalação:
mix coherence.install --full --rememberable --invitable --trackable
Execute mix help coherence.install para ver a descrição de todas as opções.
E se você não estiver ajustando o front-end, você pode simplesmente adicionar os links corretos de Cadastro, sign in e sign out, adicionando o fragmento de código abaixo ao caminho web/templates/layout/app.html.eex
<header class="header"> <nav role="navigation"> <ul class="nav nav-pills pull-right"> <%= if Coherence.current_user(@conn) do %> <%= if @conn.assigns[:remembered] do %> <li style="color: red;">!!</li> <% end %> <% end %> <%= YourApp.Coherence.ViewHelpers.coherence_links(@conn, :layout) %> <li><a href="http://www.phoenixframework.org/docs">Get Started</a></li> </ul> </nav> <span class="logo"></span> </header> ...
(A propósito, sempre que você ver “YourApp” nos fragmentos de código, você deve alterar para o nome do módulo de seu aplicativo.)
Se você se perder na documentação você pode olhar o repositório Demo deles para ver o exemplo de um aplicativo básico Phoenix com o Coherece já configurado e funcionando. Você terá que tomar muito cuidado com o “web/router.ex” para criar o “:protected pipeline” e configurar os escopos corretamente.
Se você fizer corretamente, isso é o que aparecerá:
Fazia muito tempo que eu não me animava com uma simples página de Log In
ExAdmin (Alternativa para o ActiveAdmin)
Então, o próximo passo é adicionar uma interface simples de administração. Para isso eu encontrei o ExAdmin, que está em um desenvolvimento pesado desde maio de 2015. É tão parecido com o ActiveAdmin que o seu tema fará você esquecer que não está em uma aplicação Rails.
Novamente, é bem direto para configurar somente seguindo as instruções de seu README.
Assim que você tiver instalado e configurado, você pode rapidamente exibir o modelo de usuário na interface do Admin assim:
mix admin.gen.resource User
E podemos editar o web/admin/user.ex com o seguinte:
defmodule YourApp.ExAdmin.User do use ExAdmin.Register register_resource YourApp.User do index do selectable_column column :id column :name column :email column :last_sign_in_at column :last_sign_in_ip column :sign_in_count end show _user do attributes_table do row :id row :name row :email row :reset_password_token row :reset_password_sent_at row :locked_at row :unlock_token row :sign_in_count row :current_sign_in_at row :last_sign_in_at row :current_sign_in_ip row :last_sign_in_ip end end form user do inputs do input user, :name input user, :email input user, :password, type: :password input user, :password_confirmation, type: :password end end end end
Sim, é sinistramente similar ao ActiveAdmin DSL. Ponto positivo para a equipe responsável, e isso realmente mostra como o Elixir funciona bem para Linguagens de Domínio Específico, se você está nessa.
Se você seguiu as intruções do Coherence, ele pede para você adicionar um “:protected pipeline”(uma coleção de conexões) para suas rotas protegidas. Por enquanto você pode adicionar a rota “/admin” para passar por esse canal. E para os “Não iniciados”, essas “conexões” são similares ao conceito do aplicativo Rack, ou mais especificamente, um middleware de Rails. Mas em Rails, nós temos apenas um canal de middlewares. No Phoenix, podemos configurar múltiplos canais para diferentes tipos de rotas (navegador e API, por exemplo).
Então, podemos adicionar o seguinte ao “web/router.ex”
... scope "/admin", ExAdmin do pipe_through :protected admin_routes end ...
Com esses simples dispositivos configurados, você terá algo assim:
E se você ainda não estiver convencido, que tal mudar o tema antigo?
Agora sim! Faz eu me sentir em casa, embora eu realmente prefira o tema novo. Mas você pode substituir seu aplicativo baseado no ActiveAdmin por esse e seus usuários dificilmente notarão as pequenas diferenças na interface. Os comportamentos são praticamente os mesmos.
Se você ainda tem perguntas sobre como configurar corretamente o ExAdmin, verifique o projeto Contact Demo deles, onde você pode encontrar um exemplo real.
Criação de uma função de administrador simples
Obviamente, não queremos deixar todos os usuários logados acessarem a sessão de Admin.
Então, podemos adicionar um campo booleano simples na tabela de usuários para indicar se ele é administrador ou não. Você pode mudar sua migração para:
... def change do create table(:users, primary_key: false) do add :name, :string add :email, :string ... add :admin, :boolean, default: false ... end end ...
E você pode configurar o arquivo “priv/repos/seeds.exs” para criar dois usuários, um administrador e um convidado:
YourApp.Repo.delete_all YourApp.User YourApp.User.changeset(%YourApp.User{}, %{name: "Administrator", email: "admin@example.org", password: "password", password_confirmation: "password", admin: true}) |> YourApp.Repo.insert! YourApp.User.changeset(%YourApp.User{}, %{name: "Guest", email: "guest@example.org", password: "password", password_confirmation: "password", admin: false}) |> YourApp.Repo.insert!
Como isso é somente um exercício, você pode apagar o banco de dados e criar novamente, assim: mix do ecto.drop, ecto.setup.
O Coherence cuida da autenticação, mas temos que cuidar da autorização. Você vai encontrar muitos exemplos online para algo que lembre o Pundit do Rails, como o Bodyguard. Mas para esse post vou ficar com uma conexão simples e criar um novo canal.
Vamos precisar criar o arquivo “lib/your_app/plugs/authorized.ex” e adicionar o seguinte:
defmodule YourApp.Plugs.Authorized do @behaviour Plug import Plug.Conn import Phoenix.Controller def init(default), do: default def call(%{assigns: %{current_user: current_user}} = conn, _) do if current_user.admin do conn else conn |> flash_and_redirect end end def call(conn, _) do conn |> flash_and_redirect end defp flash_and_redirect(conn) do conn |> put_flash(:error, "You do not have the proper authorization to do that") |> redirect(to: "/") |> halt end end
Assim que o usuário entrar, o Coherence coloca a estrutura de usuário autenticado no “conn” (uma estrutura Plug.Conn), para que possamos combinar os padrões.
Agora, precisamos criar o canal em “web/router.ex” assim:
... pipeline :protected_admin do plug :accepts, ["html"] plug :fetch_session plug :fetch_flash plug :protect_from_forgery plug :put_secure_browser_headers plug Coherence.Authentication.Session, protected: true plug YourApp.Plugs.Authorized end ... scope "/" do pipe_through :protected_admin coherence_routes :protected_admin end ... scope "/admin", ExAdmin do pipe_through :protected_admin admin_routes end ...
O canal “:protected_admin” é exatamente o mesmo de “:protected” mas nós adicionamos o recém criado YourApp.Plugs.Authorized no fim. E então nós mudamos o escopo do “/admin” para passar por esse canal.
É isso. Se você entrar com o usuário “guest@example.org”, ele vai ser enviado para a página inicial com uma mensagem dizendo que ele não é autorizado. Se você entrar com o usuário “admin@example.org”, você poderá acessar a interface ExAdmin em /admin.
Finalizando
Mesmo que agora seja super simples adicionar a autenticação, administração e autorização básica, não se engane, a curva de aprendizado ainda é íngreme, mesmo que você seja desenvolvedor Rails há um tempo.
Devido ao que está por baixo, a arquitetura OTP, os conceitos de aplicações supervisores, trabalhadores, etc, não é imediatamente simples de entender o que está realmente acontecendo. Se você não for cuidadoso, as bibliotecas com o Coherence ou ExAdmin vão fazer você achar que é tão simples quanto em Rails.
E não é assim. Elixir é completamente diferente. E eu digo que é de uma maneira ruim, é exatamente o contrário. É desenvolvido para sistemas distribuídos e altamente confiáveis e demanda muito mais conhecimento, paciência e treinamento do programador.
Por outro lado, exatamente por causa das bibliotecas como o Coherence que tornam mais fácil o início, você pode ficar mais motivado a criar alguma coisa e colocar para rodar, e então investir mais tempo realmente entendendo o que acontece por baixo. Então, a recomendação é: suje suas mãos, tenha alguma gratificação rápida de ver algo rodando, então vá em frente e refine seu conhecimento. Será mais gratificante se você fizer assim.
Eu não vejo o Phoenix sendo somente um substituto para Rails. Seria fácil demais. Eu vejo mais como uma outra peça para que o Elixir seja a melhor escolha para construirmos sistemas altamente distribuídos, altamente confiáveis e altamente escaláveis. Para em simples aplicações web não utilizaria todo o potencial do Elixir.
***
Artigo traduzido com autorização do autor. Publicado originalmente em http://www.akitaonrails.com/2016/12/06/coherence-and-exadmin-devise-and-activeadmin-for-phoenix.