Como gerenciar sessões com o Firestore

Muitos aplicativos precisam gerenciar sessões de autenticação e preferências do usuário. O Sinatra tem uma implementação baseada em memória para executar essa função. No entanto, essa implementação não é adequada para um app que pode ser veiculado de várias instâncias, porque a sessão gravada em uma instância pode ser diferente nas outras. Veja neste tutorial como gerenciar sessões no App Engine.

Objetivos

  • Gravar o aplicativo.
  • Executar o aplicativo localmente.
  • Implantar o aplicativo no App Engine.

Custos

Neste tutorial, usamos os seguintes componentes faturáveis do Google Cloud:

Para gerar uma estimativa de custo baseada na projeção de uso deste tutorial, use a calculadora de preços. Novos usuários do Google Cloud podem estar qualificados para uma avaliação gratuita.

Ao concluir este tutorial, exclua os recursos criados para evitar o faturamento contínuo. Para mais informações, consulte Como fazer a limpeza.

Antes de começar

  1. Faça login na sua Conta do Google.

    Se você ainda não tiver uma, inscreva-se.

  2. No Console do Cloud, na página de seletor de projetos, selecione ou crie um projeto do Cloud.

    Acesse a página do seletor de projetos

  3. Verifique se a cobrança está ativada para o seu projeto do Google Cloud. Saiba como confirmar se a cobrança está ativada para o seu projeto.

  4. Ative a API Firestore.

    Ative a API

  5. Prepare seu ambiente para desenvolvedores.

Como configurar o projeto

  1. Na janela de terminal, inicie em um diretório de sua escolha e crie um novo diretório chamado sessions. Todo o código deste tutorial está dentro do diretório sessions.

  2. Mude para o diretório sessions:

    cd sessions
    
  3. Inicialize o Gemfile:

    bundle init
    
  4. Anexe o seguinte ao Gemfile resultante:

    gem "google-cloud-firestore", "~> 1.2"
    gem "sinatra", "~> 2.0"

    O Gemfile lista todas as bibliotecas do Ruby não padrão que seu aplicativo precisa do App Engine para carregar:

    • google-cloud-firestore é o cliente Ruby para a API Firestore.

    • Sinatra é o framework da Web do Ruby usado para o app.

  5. Instale as dependências:

    bundle install
    

Como gravar o app da Web

Esse aplicativo exibe saudações em idiomas diferentes para cada usuário. Os usuários retornantes são sempre recebidos no mesmo idioma.

  • Com um editor de texto, crie um arquivo chamado app.rb no diretório sessions com este conteúdo:

    require "sinatra"
    
    require_relative "firestore_session"
    
    use Rack::Session::FirestoreSession
    
    set :greetings, ["Hello World", "Hallo Welt", "Ciao Mondo", "Salut le Monde", "Hola Mundo"]
    
    get "/" do
      session[:greeting] ||= settings.greetings.sample
      session[:views] ||= 0
      session[:views] += 1
      "<h1>#{session[:views]} views for \"#{session[:greeting]}\"</h1>"
    end

Como criar o armazenamento de sessão

Para que o app possa armazenar as preferências de um usuário, você precisa de uma maneira de armazenar informações sobre o usuário atual em uma sessão. Veja no diagrama a seguir como o Firestore gerencia as sessões do aplicativo do App Engine.

Diagrama da arquitetura: usuário, App Engine, Firestore.

O Sinatra tem suporte integrado para salvar dados da sessão em um cookie. Para salvar no Firestore, é preciso definir seu próprio objeto Rack::Session.

  • No diretório sessions, crie um arquivo chamado firestore_session.rb com este conteúdo:

    require "google/cloud/firestore"
    require "rack/session/abstract/id"
    
    module Rack
      module Session
        class FirestoreSession < Abstract::Persisted
          def initialize app, options = {}
            super
    
            @firestore = Google::Cloud::Firestore.new
            @col = @firestore.col "sessions"
          end
    
          def find_session _req, session_id
            return [generate_sid, {}] if session_id.nil?
    
            doc = @col.doc session_id
            fields = doc.get.fields || {}
            [session_id, stringify_keys(fields)]
          end
    
          def write_session _req, session_id, new_session, _opts
            doc = @col.doc session_id
            doc.set new_session, merge: true
            session_id
          end
    
          def delete_session _req, session_id, _opts
            doc = @col.doc session_id
            doc.delete
            generate_sid
          end
    
          def stringify_keys hash
            new_hash = {}
            hash.each do |k, v|
              new_hash[k.to_s] =
                if v.is_a? Hash
                  stringify_keys v
                else
                  v
                end
            end
            new_hash
          end
        end
      end
    end

Como excluir sessões

Conforme descrito, este app não exclui sessões antigas ou expiradas. É possível excluir os dados da sessão no Console do Google Cloud ou implementar uma estratégia de exclusão automática.

Como executar no local

  1. Inicie o servidor HTTP:

    bundle exec ruby app.rb
    
  2. Veja seu app no navegador da Web:

    Você verá uma das cinco saudações: "Hello World", "Hallo Welt", "Hola mundo", "Salut le Monde" ou "Ciao Mondo." O idioma será alterado se você abrir a página em um navegador diferente ou no modo de navegação anônima. Veja e edite os dados da sessão no Console do Google Cloud.

  3. Para interromper o servidor HTTP, pressione Control+C na janela do terminal.

Como implantar e executar no App Engine

Use o ambiente padrão do App Engine para criar e implantar um aplicativo que seja executado de forma confiável sob carga pesada e com grandes quantidades de dados.

Neste tutorial, o ambiente padrão do App Engine é usado para implantar o servidor.

  1. Na sua janela de terminal, crie um arquivo app.yaml e cole o seguinte nele:

    runtime: ruby25
    entrypoint: bundle exec ruby app.rb
  2. Implante o aplicativo no App Engine:

    gcloud app deploy
    
  3. Veja o aplicativo ativo no URL a seguir, em que PROJECT_ID é o ID do projeto no Google Cloud:

    https://PROJECT_ID.appspot.com

A saudação agora é entregue por um servidor da Web em execução em uma instância do App Engine.

Como depurar o aplicativo

Se você não conseguir se conectar ao aplicativo do App Engine, verifique o seguinte:

  1. Verifique se os comandos de implantação gcloud foram concluídos com êxito e não geraram erros. Se houver erros (por exemplo, message=Build failed), corrija-os e tente implantar o aplicativo do App Engine novamente.
  2. No Console do Cloud, acesse a página visualizador de registros.

    Acesse a página do visualizador de registros

    1. Na lista suspensa Recursos selecionados recentemente, clique em Aplicativo App Engine e, em seguida, clique em Todos os module_id. Você verá uma lista de solicitações de quando visitou seu aplicativo. Caso contrário, verifique se você selecionou Todos os module_id na lista suspensa. Se você vir mensagens de erro impressas no Console do Cloud, verifique se o código do aplicativo corresponde ao código na seção sobre como gravar o app da Web.

    2. Verifique se a API do Cloud Firestore está ativada.

Limpar

Excluir o projeto

  1. No Console do Cloud, acesse a página Gerenciar recursos:

    Acessar a página Gerenciar recursos

  2. Na lista de projetos, selecione o projeto que você quer excluir e clique em Excluir .
  3. Na caixa de diálogo, digite o ID do projeto e clique em Encerrar para excluí-lo.

Excluir a instância do App Engine

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

    Acessar a página "Versões"

  2. Marque a caixa de seleção da versão não padrão do app que você quer excluir.
  3. Clique em Excluir para remover a versão do app.

A seguir