- Gerar link
- X
- Outros aplicativos
O que é autenticação baseada em token?
A autenticação baseada em token (também conhecida como autenticação JSON Web Token ) é uma nova maneira de lidar com a autenticação de usuários em aplicativos. É uma alternativa à autenticação baseada em sessão .
A diferença mais notável entre a autenticação baseada em sessão e a autenticação baseada em token é que a autenticação baseada em sessão depende muito do servidor. Um registro é criado para cada usuário conectado.
A autenticação baseada em token não tem estado - ela não armazena nada no servidor, mas cria um token codificado exclusivo que é verificado toda vez que uma solicitação é feita.
Ao contrário da autenticação baseada em sessão, uma abordagem de token não associa um usuário com informações de login, mas com um token exclusivo que é usado para transportar transações cliente-host. Muitos aplicativos, incluindo Facebook, Google e GitHub, usam a abordagem baseada em tokens.
Benefícios da autenticação baseada em token
Existem vários benefícios em usar essa abordagem:
Domínio cruzado / CORS
Cookies e CORS não combinam bem em domínios diferentes. Uma abordagem baseada em token permite que você faça chamadas AJAX para qualquer servidor, em qualquer domínio, porque você usa um cabeçalho HTTP para transmitir as informações do usuário.
Sem estado
Os tokens são sem estado. Não há necessidade de manter um armazenamento de sessão, pois o token é uma entidade independente que armazena todas as informações do usuário nele.
Dissociação
Você não está mais vinculado a um esquema de autenticação específico. Os tokens podem ser gerados em qualquer lugar, de modo que a API pode ser chamada de qualquer lugar com um único comando autenticado em vez de várias chamadas autenticadas.
Pronto para celular
Os cookies são um problema quando se trata de armazenar informações do usuário em aplicativos móveis nativos. A adoção de uma abordagem baseada em tokens simplifica significativamente esse processo de economia.
CSRF (Cross Site Request Forgery)
Como o aplicativo não depende de cookies para autenticação, ele é invulnerável a ataques de solicitação entre sites.
atuação
Em termos de carga do lado do servidor, uma viagem de ida e volta na rede (por exemplo, encontrar uma sessão em um banco de dados) provavelmente levará mais tempo do que calcular um código HMACSHA256 para validar um token e analisar seu conteúdo. Isso torna a autenticação baseada em token mais rápida do que a alternativa tradicional.
Como funciona a autenticação baseada em token?
A maneira como a autenticação baseada em tokens funciona é simples. O usuário insere suas credenciais e envia uma solicitação ao servidor. Se as credenciais estiverem corretas, o servidor criará um token codificado HMACSHA256 exclusivo, também conhecido como token da web JSON (JWT). O cliente armazena o JWT e faz todas as solicitações subsequentes ao servidor com o token anexado. O servidor autentica o usuário comparando o JWT enviado com a solicitação àquele que ele armazenou no banco de dados. Aqui está um diagrama simples do processo:
O que um token JWT contém?
O token é separado em três valores separados por pontos codificados em base 64. Cada valor representa um tipo diferente de dados:
Cabeçalho
Consiste no tipo de token (JWT) e no tipo de algoritmo de criptografia (HS256) codificado na base 64.
Carga útil
A carga útil contém informações sobre o usuário e sua função. Por exemplo, a carga útil do token pode conter o e-mail e a senha.
Assinatura
A assinatura é uma chave única que identifica o serviço que cria o cabeçalho. Nesse caso, a assinatura do token será uma versão codificada em base 64 da chave secreta do aplicativo Rails ( Rails.application.secrets.secret_key_base
). Como cada aplicativo tem uma chave base exclusiva, essa chave secreta serve como assinatura de token.
Configurando uma autenticação baseada em token com Rails 5
Chega de teoria, é hora de praticar. A primeira etapa é criar um novo aplicativo Rails 5 apenas API:
1rails _5.0.0.beta3_ new api-app --api
Ao anexar --api
no final do gerador, um aplicativo somente API será criado. Aplicativos somente API são adições recentes à plataforma Rails. Um aplicativo API é uma versão reduzida do aplicativo Rails padrão sem nenhum middleware desnecessário, como .erb
visualizações, ajudantes e ativos. Os aplicativos API vêm com middlewares especiais, como ActionController::API
aceleração de solicitação, configuração fácil de CORS e outros recursos personalizados dispensados para a construção de APIs.
Existem vários requisitos que precisam ser atendidos antes de podermos usar a abordagem baseada em tokens:
- Precisamos de um modelo acessível.
- Uma maneira de codificar e decodificar tokens JWT deve ser implementada.
- Precisamos de métodos para verificar se o usuário está autenticado.
- Controladores para criar e fazer login de usuários também são necessários.
- Precisamos de rotas para a criação de usuários e seu login e logout.
Criação do modelo de usuário
Primeiro, o modelo de usuário deve ser criado:
1 rails g model User name email password_digest
Execute as migrações:
1 rails db:migrate
Ao executar esses métodos, criamos um modelo de usuário com os campos de nome, e-mail e senha e temos seu esquema migrado no banco de dados.
O método has_secure_password
deve ser adicionado ao modelo para garantir que a senha esteja devidamente criptografada no banco de dados: has_secure_password
é parte do bcrypt
gem, portanto, temos que instalá-lo primeiro. Adicione ao gemfile:
1#Gemfile.rb
2gem 'bcrypt', '~> 3.1.7'
E instale-o:
1 bundle install
Com a gema instalada, o método pode ser incluído no modelo:
1#app/models/user.rb
2
3class User < ApplicationRecord
4 has_secure_password
5end
Tokens JWT de codificação e decodificação
Assim que o modelo do usuário for concluído, a implementação da geração do token JWT pode começar. Primeiro, a jwt
gem tornará a codificação e decodificação de tokens HMACSHA256 disponíveis no aplicativo Rails. Primeiro:
1 gem 'jwt'
Em seguida, instale-o:
1bundle install
Uma vez que o gem é instalado, ele pode ser acessado através da JWT
variável global. Como os métodos que serão usados exigem encapsulamento, uma classe singleton é uma ótima maneira de envolver a lógica e usá-la em outras construções.
Para aqueles que não estão familiarizados, uma classe singleton restringe a instanciação de uma classe a um único objeto, o que é útil quando apenas um objeto é necessário para completar as tarefas em mãos.
1# lib/json_web_token.rb
2
3class JsonWebToken
4 class << self
5 def encode(payload, exp = 24.hours.from_now)
6 payload[:exp] = exp.to_i
7 JWT.encode(payload, Rails.application.secrets.secret_key_base)
8 end
9
10 def decode(token)
11 body = JWT.decode(token, Rails.application.secrets.secret_key_base)[0]
12 HashWithIndifferentAccess.new body
13 rescue
14 nil
15 end
16 end
17end
O primeiro método encode
,, usa três parâmetros - o ID do usuário, o tempo de expiração (1 dia) e a chave de base única de seu aplicativo Rails - para criar um token único.
O segundo método decode
,, pega o token e usa a chave secreta do aplicativo para decodificá-lo.
Aqui estão os dois casos em que esses métodos serão usados:
- Para autenticar o usuário e gerar um token para ele utilizar
encode
. - Para verificar se o token do usuário anexado em cada solicitação está correto, use
decode
.
Para ter certeza de que tudo funcionará, o conteúdo do lib
diretório deve ser incluído quando o aplicativo Rails for carregado.
1 #config/application.rb
2module ApiApp
3 class Application < Rails::Application
4 #.....
5 config.autoload_paths << Rails.root.join('lib')
6 #.....
7 end
8 end
Autenticação de usuários
Em vez de usar métodos de controlador privado, simple_command
pode ser usado. Para obter mais informações sobre a instalação, consulte o artigo simple_command .
O comando simples gem é uma maneira fácil de criar serviços. Sua função é semelhante à de um auxiliar, mas facilita a conexão entre o controlador e o modelo, em vez do controlador e a visualização. Desta forma, podemos encurtar o código nos modelos e controladores.
Adicione a joia ao seu Gemfile
:
1gem 'simple_command'
E agrupe-o:
1bundle install
Então, os métodos de apelido do simple_command
podem ser facilmente usados em uma classe por escrito prepend SimpleCommand
. Aqui está como um comando é estruturado:
1class AuthenticateUser
2 prepend SimpleCommand
3
4 def initialize()
5 #this is where parameters are taken when the command is called
6 end
7
8 def call
9 #this is where the result gets returned
10 end
11
12end
O comando obtém o e-mail e a senha do usuário e retorna o usuário, se as credenciais corresponderem. Veja como isso pode ser feito:
1# app/commands/authenticate_user.rb
2
3class AuthenticateUser
4 prepend SimpleCommand
5
6 def initialize(email, password)
7 @email = email
8 @password = password
9 end
10
11 def call
12 JsonWebToken.encode(user_id: user.id) if user
13 end
14
15 private
16
17 attr_accessor :email, :password
18
19 def user
20 user = User.find_by_email(email)
21 return user if user && user.authenticate(password)
22
23 errors.add :user_authentication, 'invalid credentials'
24 nil
25 end
26end
O comando leva os parâmetros e inicializa uma instância de classe com email
e password
atributos que são acessíveis dentro da classe. O método privado user
usa as credenciais para verificar se o usuário existe no banco de dados usando User.find_by_email
.
Se o usuário for encontrado, o método usa o método integrado authenticate
. Este método pode estar disponível colocando has_secure_password no modelo de usuário para verificar se a senha do usuário está correta. Se tudo for verdade, o usuário será devolvido. Caso contrário, o método retornará nil
.
Verificando a autorização do usuário
A criação do token está concluída, mas não há como verificar se um token que foi anexado a uma solicitação é válido. O comando para autorização deve obter o headers
da solicitação e decodificar o token usando o decode
método no JsonWebToken
singleton.
Uma atualização sobre os cabeçalhos:
As solicitações Http têm campos conhecidos como cabeçalhos . Os cabeçalhos podem conter uma ampla variedade de informações sobre a solicitação que podem ser úteis para o servidor que a interpreta. Por exemplo, um cabeçalho pode conter o formato do corpo da solicitação, informações de autorização e outras meta informações (você pode encontrar todos os tipos aqui ). Os tokens são geralmente anexados ao cabeçalho 'Autorização'.
Aqui está como o código está estruturado:
1# app/commands/authorize_api_request.rb
2
3class AuthorizeApiRequest
4 prepend SimpleCommand
5
6 def initialize(headers = {})
7 @headers = headers
8 end
9
10 def call
11 user
12 end
13
14 private
15
16 attr_reader :headers
17
18 def user
19 @user ||= User.find(decoded_auth_token[:user_id]) if decoded_auth_token
20 @user || errors.add(:token, 'Invalid token') && nil
21 end
22
23 def decoded_auth_token
24 @decoded_auth_token ||= JsonWebToken.decode(http_auth_header)
25 end
26
27 def http_auth_header
28 if headers['Authorization'].present?
29 return headers['Authorization'].split(' ').last
30 else
31 errors.add(:token, 'Missing token')
32 end
33 nil
34 end
35end
Este código executa uma cadeia de métodos. Vamos começar de baixo e continuar até o topo.
http_auth_header
O último método na cadeia http_auth_header
,, extrai o token do cabeçalho de autorização recebido na inicialização da classe.
decoded_auth-token
O método anterior na cadeia é decoded_auth_token
, que decodifica o token recebido http_auth_header
e recupera o ID do usuário.
do utilizador
A lógica do user
método pode parecer abstrata, então vamos examiná-la linha por linha.
Na primeira linha, o ||=
operador é usado para atribuir @user
atribuindo "se não nil
". Basicamente, se o User.find()
retorna um conjunto vazio ou decoded_auth_token
retorna falso, @user
será nil
.
Passando para a segunda linha, o user
método retornará o usuário ou gerará um erro. Em Ruby, a última linha da função é retornada implicitamente, então o comando acaba retornando o objeto do usuário.
Implementando métodos auxiliares nos controladores
Toda a lógica para lidar com tokens JWT foi estabelecida. É hora de implementá-lo nos controladores e colocá-lo em uso real. As duas partes mais essenciais a serem implementadas são a identificação do login do usuário e a referência ao usuário atual.
Usuários de login
Primeiro, vamos começar com o login do usuário:
1# app/controllers/authentication_controller.rb
2
3class AuthenticationController < ApplicationController
4 skip_before_action :authenticate_request
5
6 def authenticate
7 command = AuthenticateUser.call(params[:email], params[:password])
8
9 if command.success?
10 render json: { auth_token: command.result }
11 else
12 render json: { error: command.errors }, status: :unauthorized
13 end
14 end
15end
A authenticate
ação pegará os parâmetros JSON para e-mail e senha por meio do params
hash e os passará para o AuthenticateUser
comando. Se o comando for bem-sucedido, ele enviará o token JWT de volta ao usuário.
Vamos colocar um ponto final para a ação:
1 #config/routes.rb
2 post 'authenticate', to: 'authentication#authenticate'
Solicitações de autorização
Para colocar o token em uso, deve haver um current_user
método que irá 'persistir' o usuário. Para estar à current_user
disposição de todos os controladores, deve ser declarado em ApplicationController
:
1#app/controllers/application_controller.rb
2class ApplicationController < ActionController::API
3 before_action :authenticate_request
4 attr_reader :current_user
5
6 private
7
8 def authenticate_request
9 @current_user = AuthorizeApiRequest.call(request.headers).result
10 render json: { error: 'Not Authorized' }, status: 401 unless @current_user
11 end
12end
Ao usar before_action
, o servidor passa os cabeçalhos da solicitação (usando a propriedade do objeto embutido request.headers
) para AuthorizeApiRequest
cada vez que o usuário faz uma solicitação. Chamando result
on AuthorizeApiRequest.call(request.headers)
é proveniente do SimpleCommand
módulo, onde é definido como attr_reader :result
. Os resultados da solicitação são devolvidos ao @current_user
, tornando-se disponíveis para todos os controladores herdados de ApplicationController
.
Funciona?
Vamos ver como tudo funciona. Inicie o console Rails no diretório raiz do aplicativo:
1rails c
Crie um usuário e insira-o no console:
1User.create!(email: 'example@mail.com' , password: '123123123' , password_confirmation: '123123123')
Para ver como a autorização funciona, deve haver um recurso que deve ser solicitado. Vamos criar um recurso. Em seu terminal, execute:
1rails g scaffold Item name:string description:text
Isso criará um recurso nomeado Item
de cima para baixo - um modelo, um controlador, rotas e visualizações. Migre o banco de dados:
1rails db:migrate
Agora, inicie o servidor e use cURL para postar as credenciais localhost:3000/authenticate
. Esta é a aparência da solicitação:
1$ curl -H "Content-Type: application/json" -X POST -d '{"email":"example@mail.com","password":"123123123"}' http://localhost:3000/authenticate
Seu token será devolvido.
1{"auth_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJleHAiOjE0NjA2NTgxODZ9.xsSwcPC22IR71OBv6bU_OGCSyfE89DvEzWfDU0iybMA"}
Excelente! Um token foi gerado. Vamos verificar se o recurso está acessível. Você pode fazer isso fazendo uma GET
solicitação para localhost:3000/items
:
1$ curl http://localhost:3000/items
2{"error":"Not Authorized"}
O recurso não está acessível porque o token não foi anexado aos cabeçalhos da solicitação. Copie o token gerado anteriormente e coloque-o no Authorization
cabeçalho:
1$ curl -H "Authorization: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJleHAiOjE0NjA2NTgxODZ9.xsSwcPC22IR71OBv6bU_OGCSyfE89DvEzWfDU0iybMA" http://localhost:3000/items
2[]
Com o token prefixado, um array vazio ( []
) é retornado. Isso é normal - depois de adicionar quaisquer itens, você os verá retornados na solicitação.
Incrível! Tudo funciona.
Se você perdeu algo, o projeto foi carregado no GitHub . Se você tiver alguma dúvida, sinta-se à vontade para me enviar uma mensagem no Github.
Usamos cookies para tornar as interações com nossos sites e serviços fáceis e significativas. Para obter mais informações sobre os cookies que usamos ou para saber como você pode desativar os cookies, clique aqui.
- Gerar link
- X
- Outros aplicativos
Comentários
Postar um comentário