Como autenticar usuários com Ruby

Nesta parte do tutorial do aplicativo Bookshelf, mostramos como criar um fluxo de trabalho de entrada para usuários e como usar as informações de perfil para oferecer uma funcionalidade personalizada aos usuários.

Use o Google Identity Platform, para ter fácil acesso a informações sobre seus usuários e a certeza de que as credenciais de login deles sejam gerenciadas com segurança pelo Google. Use o OAuth 2.0 para fornecer um fluxo de trabalho de login para todos os usuários do seu aplicativo. Ele concede ao aplicativo o acesso a informações básicas de perfil sobre os usuários autenticados.

Esta página faz parte de um tutorial com várias páginas. Para começar do início e ver as instruções de configuração, consulte Aplicativo Bookshelf em Ruby.

Como criar um ID do cliente do aplicativo da Web

Com um ID do cliente do aplicativo da Web, seu aplicativo autoriza usuários e acesso às APIs do Google.

  1. No Console do Google Cloud Platform, acesse a página Credenciais.

    Acessar a página "Credenciais"

  2. Clique na Tela de consentimento do OAuth.

  3. Digite Ruby Bookshelf App como nome do produto.

  4. Em Domínios autorizados, adicione o nome do aplicativo do App Engine como [YOUR_PROJECT_ID].appspot.com.

    Substitua [YOUR_PROJECT_ID] pelo ID do projeto do GCP.

  5. Preencha todos os outros campos relevantes e opcionais. Em seguida, clique em Salvar.

  6. Clique em Criar credenciais > ID do cliente OAuth.

  7. Na lista suspensa Tipo de aplicativo, clique em Aplicativo da Web.

  8. No campo Nome, digite Ruby Bookshelf Client.

  9. No campo URIs de redirecionamento autorizado, insira os URLs a seguir, um de cada vez.

    http://localhost:3000/auth/google_oauth2/callback
    http://[YOUR_PROJECT_ID].appspot.com/auth/google_oauth2/callback
    https://[YOUR_PROJECT_ID].appspot.com/auth/google_oauth2/callback

  10. Clique em Criar.

  11. Copie o ID do cliente e a chave secreta do cliente e salve-os para uso posterior.

Como instalar dependências

Acesse o diretório getting-started-ruby/4-auth e digite este comando:

bundle install

Como definir as configurações

  1. Copie o arquivo de configurações de exemplo.

    cp config/settings.example.yml config/settings.yml
    
  2. Edite o arquivo settings.yml. Substitua [YOUR_CLIENT_ID] pelo ID do cliente do seu aplicativo da Web e [YOUR_CLIENT_SECRET] pela chave secreta do aplicativo da Web.

    default: &default
      oauth2:
        client_id: [YOUR_CLIENT_ID]
        client_secret: [YOUR_CLIENT_SECRET]
    
  3. No arquivo settings.yml, substitua os valores de project_id e gcs_bucket pelos valores usados na seção Como usar o Cloud Storage.

    Por exemplo, suponha que o ID do cliente do aplicativo da Web seja XYZCLIENTID, a chave secreta do cliente seja XYZCLIENTSECRET, o nome do projeto seja my-project e o nome do intervalo do Cloud Storage seja my-bucket. Então, a seção padrão do seu arquivo settings.yml ficaria assim:

    default: &default
      project_id: my-project
      gcs_bucket: my-bucket
      oauth2:
        client_id: XYZCLIENTID
        client_secret: XYZCLIENTSECRET
    
  4. Copie o arquivo database.example.yml.

    cp config/database.example.yml config/database.yml
    
  5. Configure o aplicativo de amostra para usar o mesmo banco de dados que você configurou durante a parte Como usar dados estruturados deste tutorial:

    Cloud SQL

    • Edite o arquivo database.yml. Remova os comentários das linhas da parte do Cloud SQL no arquivo.

       mysql_settings: &mysql_settings
         adapter: mysql2
         encoding: utf8
         pool: 5
         timeout: 5000
         username: [MYSQL_USER]
         password: [MYSQL_PASS]
         database: [MYSQL_DATABASE]
         socket: /cloudsql/[YOUR_INSTANCE_CONNECTION_NAME]
      
      • Substitua [MYSQL_USER] e [MYSQL_PASS] pelo nome de usuário e pela senha da instância do Cloud SQL criados anteriormente.

      • Substitua [MYSQL_DATABASE] pelo nome do banco de dados criado anteriormente.

      • Substitua [YOUR_INSTANCE_CONNECTION_NAME] pelo Instance Connection Name da instância do Cloud SQL.

    • Execute as migrações.

      bundle exec rake db:migrate
      

    PostgreSQL

    • Edite o arquivo database.yml. Remova os comentários das linhas da parte do PostgreSQL no arquivo. Substitua os marcadores your-postgresql-* pelos valores do banco de dados e da instância do PostgreSQL. Por exemplo, suponha que seu endereço IPv4 seja 173.194.230.44, seu nome de usuário seja postgres, sua senha seja pword123 e o nome do seu banco de dados seja bookshelf. Então, a parte do PostgreSQL do seu arquivo database.yml seria assim:

      # PostgreSQL Sample Database Configuration
      # ----------------------------------------
        adapter: postgresql
        encoding: unicode
        pool: 5
        username: postgres
        password: pword123
        host: 173.194.230.44
        database: bookshelf
      
    • Crie as tabelas e o banco de dados necessários.

      bundle exec rake db:create
      bundle exec rake db:migrate
      

    Cloud Datastore

    • Edite o arquivo database.yml. Remova os comentários da linha na parte do Cloud Datastore no arquivo. Substitua your-project-id pelo código do projeto do Google Cloud Platform. Por exemplo, se o código do projeto for my-project, a parte do Cloud Datastore do arquivo database.yml será assim:

      # Google Cloud Datastore Sample Database Configuration
      # ----------------------------------------------------
      dataset_id: my-project
      
    • Execute uma tarefa "rake" para copiar os arquivos do projeto de amostra para o Cloud Datastore.

      bundle exec rake backend:datastore
      

Como executar o app na máquina local

  1. Inicie um servidor da Web local.

    bundle exec rails server
    
  2. No navegador da Web, digite este endereço:

    http://localhost:3000

Agora navegue nas páginas da Web do app, faça login usando sua Conta do Google e adicione livros. Para vê-los, basta usar o link My Books na parte superior da barra de navegação.

Para sair do servidor da Web local, pressione Control+C.

Como implantar o app no ambiente flexível do App Engine

  1. Compile os recursos do JavaScript para produção.

    RAILS_ENV=production bundle exec rake assets:precompile
    
  2. Implante o app de amostra.

    gcloud app deploy
    
  3. No navegador da Web, digite o endereço a seguir.

    https://[YOUR_PROJECT_ID].appspot.com
    

Atualize o app e implante a versão atualizada com o mesmo comando usado para implantá-lo pela primeira vez. A implantação cria uma nova versão do app e a define como padrão. As versões mais antigas são mantidas, bem como as instâncias de VM associadas. Lembre-se de que essas versões do aplicativo e instâncias de VM são recursos passíveis de cobrança.

Reduza os custos excluindo as versões não padrão do app.

Para excluir uma versão do app:

  1. No Console do GCP, acesse a página "Versões do App Engine".

    Acessar a página Versões

  2. Clique na caixa de seleção ao lado da versão do aplicativo não padrão que você quer excluir.
  3. Clique no botão Excluir na parte superior da página para excluir a versão do aplicativo.

Para informações detalhadas sobre a remoção de recursos faturáveis, consulte a seção Como fazer a limpeza na etapa final deste tutorial.

Estrutura do app

O diagrama a seguir mostra os componentes do aplicativo e como eles se relacionam.

Auth sample structure

Noções básicas sobre o código

Esta seção analisa o código de amostra e explica como ele funciona.

Login do usuário

O formulário para a página inicial do aplicativo tem um novo link para os usuários fazerem login:

<%= link_to "Login", login_path %>

A rota /login é configurada no arquivo config/routes.rb:

get "/login", to: redirect("/auth/google_oauth2")

Ao clicar em Login, você será redirecionado para a tela de consentimento do usuário do Google OAuth 2.0. As gems em Ruby OmniAuth e Google OAuth2 aceitam o fluxo de trabalho de login:

gem "omniauth"
gem "omniauth-google-oauth2"

O arquivo inicializador omniauth.rb configura OmniAuth para usar o Google OAuth 2.0 no login do usuário. O código no arquivo omniauth.rb lê as definições de configuração da seção oauth2 do arquivo config/settings.yml.

Rails.application.config.middleware.use OmniAuth::Builder do
  config = Rails.application.config.x.settings["oauth2"]

  provider :google_oauth2, config["client_id"],
                           config["client_secret"],
                           image_size: 150
end

Ao clicar em Permitir na tela de consentimento do usuário do Google OAuth 2.0, o serviço de autorização emite uma solicitação HTTP GET para a rota /auth/google_oauth2/callback do aplicativo de amostra, que está configurada no arquivo routes.rb.

get "/auth/google_oauth2/callback", to: "sessions#create"

resource :session, only: [:create, :destroy]

O manipulador da rota da chamada de retorno é o método create da classe SessionController do aplicativo de amostra. A variável de solicitação omniauth.auth fornece as informações do perfil, que incluem o identificador, o nome de exibição e a imagem de perfil. O método create lê as informações de perfil e as armazena em um objeto User que é colocado em série na seção.

class SessionsController < ApplicationController

  # Handle Google OAuth 2.0 login callback.
  #
  # GET /auth/google_oauth2/callback
  def create
    user_info = request.env["omniauth.auth"]

    user           = User.new
    user.id        = user_info["uid"]
    user.name      = user_info["info"]["name"]
    user.image_url = user_info["info"]["image"]

    session[:user] = Marshal.dump user

    redirect_to root_path
  end

A página inicial do aplicativo tem novos elementos para exibir informações sobre o usuário conectado.

<% if logged_in? %>
  <% if current_user.image_url %>
    <%= image_tag current_user.image_url, class: "img-circle", width: 24 %>
  <% end %>
  <span>
    <%= current_user.name %> &nbsp;
    <%= link_to "(logout)", logout_path %>
  </span>

Os métodos auxiliares logged_in? e current_user leem o objeto User na seção do usuário.

class ApplicationController < ActionController::Base
  helper_method :logged_in?, :current_user

  def logged_in?
    session.has_key? :user
  end

  def current_user
    Marshal.load session[:user] if logged_in?
  end

Listar os livros de um usuário

O código do usuário conectado é associado aos novos livros que ele adiciona:

def create
  @book = Book.new book_params

  @book.creator_id = current_user.id if logged_in?

  if @book.save
    flash[:success] = "Added Book"
    redirect_to book_path(@book)
  else
    render :new
  end
end

A página inicial do aplicativo tem um novo link Mine. Assim, os usuários conectados podem visualizar somente os livros que adicionaram.

<% if logged_in? %>
  <li><%= link_to "Mine", user_books_path %></li>
<% end %>

A ação index de UserBooksController consulta se há livros adicionados pelo usuário conectado.

Cloud SQL/PostgreSQL

@books = Book.where(creator_id: current_user.id).
              limit(PER_PAGE).offset(PER_PAGE * page)

Cloud Datastore

@books, @more = Book.query creator_id: current_user.id,
                           limit: PER_PAGE,
                           cursor: params[:more]
def self.query options = {}
  query = Google::Cloud::Datastore::Query.new
  query.kind "Book"
  query.limit options[:limit]   if options[:limit]
  query.cursor options[:cursor] if options[:cursor]

  if options[:creator_id]
    query.where "creator_id", "=", options[:creator_id]
  end

Saída do usuário

O formulário da página inicial do aplicativo tem um novo link logout para que os usuários possam sair.

<%= link_to "(logout)", logout_path %>

logout_path está configurado no arquivo config/routes.rb:

get "/logout", to: "sessions#destroy"

A ação destroy de SessionsController exclui o user da sessão.

def destroy
  session.delete :user

  redirect_to root_path
end
Esta página foi útil? Conte sua opinião sobre:

Enviar comentários sobre…