Introdução ao JWT em Ruby on Rails
O JSON Web Tokens é uma maneira segura e compacta de transmitir informações entre partes como um objeto JSON. Eles são comumente utilizados para autenticação e autorização em aplicativos web e móveis. Neste artigo, exploraremos como implementar JWT em uma aplicação Ruby on Rails, detalhando suas partes, vantagens e fornecendo…
O JSON Web Tokens é uma maneira segura e compacta de transmitir informações entre partes como um objeto JSON. Eles são comumente utilizados para autenticação e autorização em aplicativos web e móveis. Neste artigo, exploraremos como implementar JWT em uma aplicação Ruby on Rails, detalhando suas partes, vantagens e fornecendo um exemplo prático.
O que é JWT?
O JSON Web Tokens é um padrão aberto que define uma maneira compacta e autocontida de transmitir informações entre partes como um objeto JSON. Ele consiste em três partes principais: Header, Payload e Signature. Estas partes são codificadas em Base64Url e concatenadas por pontos (‘.’).
Estrutura do JWT
O JWT tem a seguinte estrutura:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJleHAiOjE2MTk3NTg4MDB9.tC9omCmt5rmn-ZzA5DUnI8bkL9GpZZKnPipKv2vHBEw
Header
Contém o tipo de token (JWT) e o algoritmo de criptografia usado.
{
"alg": "HS256",
"typ": "JWT"
}
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
Payload
Contém as declarações (claims), que são afirmações sobre uma entidade (geralmente o usuário) e metadados adicionais.
{
"user_id": 1,
"exp": 1619758800
}
eyJ1c2VyX2lkIjoxLCJleHAiOjE2MTk3NTg4MDB9
Signature
É usada para verificar se o token foi alterado durante a transmissão, garantindo a integridade dos dados.
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
your-256-bit-secret
)
tC9omCmt5rmn-ZzA5DUnI8bkL9GpZZKnPipKv2vHBEw
Por que usar JWT?
JWT oferece várias vantagens para a autenticação e troca de informações em aplicações web:
- Segurança: Os tokens JWT podem ser assinados digitalmente para verificar sua autenticidade e garantir que não tenham sido alterados.
- Compacto e Eficiente: Devido ao seu formato compacto em JSON, JWT é fácil de transmitir via URL, parâmetros POST ou dentro de cabeçalhos HTTP.
- Autocontido: Todas as informações necessárias sobre o usuário podem ser armazenadas no token JWT, eliminando a necessidade de consultar o banco de dados a cada requisição.
Exemplo Prático com Ruby on Rails
Vamos criar um exemplo básico de como implementar JWT em uma aplicação Ruby on Rails para autenticação de usuários.
1. Configuração do Projeto
Primeiro, crie um novo projeto Rails:
rails new jwt_example
cd jwt_example
2. Adicionando Dependências
Adicione as gems jwt
e bcrypt
ao seu Gemfile e execute bundle install
para instalar:
gem 'jwt'
gem 'bcrypt', '~> 3.1.7'
3. Criando um Serviço JWT
Crie um serviço para gerar e validar tokens JWT. Crie um arquivo app/services/json_web_token.rb
:
require 'jwt'
class JsonWebToken
SECRET_KEY = Rails.application.secrets.secret_key_base.to_s
def self.encode(payload, exp = 24.hours.from_now)
payload[:exp] = exp.to_i
JWT.encode(payload, SECRET_KEY)
end
def self.decode(token)
decoded = JWT.decode(token, SECRET_KEY)[0]
HashWithIndifferentAccess.new decoded
rescue JWT::DecodeError
nil
end
end
O serviço JsonWebToken encapsula a lógica para gerar e decodificar tokens JWT (JSON Web Token). A constante SECRET_KEY armazena a chave secreta usada para assinar os tokens, obtida da configuração da aplicação Rails (Rails.application.secrets.secret_key_base), garantindo que seja única e segura.
O método self.encode recebe um payload (dados do usuário) e um tempo de expiração (exp). Ele adiciona a expiração ao payload, codifica o payload usando a chave secreta e retorna o token JWT.
Por outro lado, o método self.decode recebe um token JWT, decodifica o token usando a chave secreta e retorna o payload. Se a decodificação falhar, seja porque o token está inválido ou expirado, ele retorna nil.
4. Controlador de Autenticação
Crie um controlador para gerenciar a autenticação dos usuários. Por exemplo, app/controllers/auth_controller.rb
:
class AuthController < ApplicationController
before_action :authorize_request, except: :login
def login
user = User.find_by(email: params[:email])
if user&.authenticate(params[:password])
token = JsonWebToken.encode(user_id: user.id)
render json: { token: token }, status: :ok
else
render json: { error: 'Invalid email or password' }, status: :unauthorized
end
end
private
def authorize_request
header = request.headers['Authorization']
header = header.split(' ').last if header
begin
@decoded = JsonWebToken.decode(header)
@current_user = User.find(@decoded[:user_id])
rescue ActiveRecord::RecordNotFound => e
render json: { errors: e.message }, status: :unauthorized
rescue JWT::DecodeError => e
render json: { errors: e.message }, status: :unauthorized
end
end
end
O AuthController gerencia as operações de login e autorização dos usuários. O método login recebe o email e a senha do usuário. Se as credenciais estiverem corretas, ele gera um token JWT e o retorna no corpo da resposta. Caso as credenciais estejam incorretas, é retornada uma mensagem de erro e status 401 Unauthorized.
O método authorize_request é um filtro de antes da ação (before_action) que verifica se a solicitação contém um token JWT válido. Ele obtém o token do cabeçalho da solicitação, decodifica o token e define o usuário atual (@current_user) com base no user_id presente no token. Se o token for inválido ou o usuário não for encontrado, retorna uma mensagem de erro e status 401 Unauthorized.
5. Configuração de Rotas
Defina as rotas para a autenticação em config/routes.rb
:
Rails.application.routes.draw do
post 'auth/login', to: 'auth#login'
end
6. Modelo de Usuário
Crie um modelo de usuário com as colunas necessárias para autenticação:
rails generate model User email:string password_digest:string
rails db:migrate
Certifique-se de ter um modelo de usuário configurado corretamente.
class User < ApplicationRecord
has_secure_password
end
A macro has_secure_password
adiciona funcionalidades para armazenar uma senha segura. Ela exige que a coluna password_digest
esteja presente no modelo.
7. Criando um Usuário
Crie um usuário diretamente via console Rails para testar a implementação de autenticação com JWT:
rails console
No console, execute:
User.create(email: '[email protected]', password: 'password', password_confirmation: 'password')
8. Testando a Implementação
Você pode testar a implementação usando ferramentas como Postman
ou curl
.
Testando com Postman
- Realizar Login
- Método:
POST
- URL:
http://localhost:3000/auth/login
- Body (raw, JSON):
json { "email": "[email protected]", "password": "password" }
- Resposta esperada:
json { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJleHAiOjE2MTk3NTg4MDB9.tC9omCmt5rmn-ZzA5DUnI8bkL9GpZZKnPipKv2vHBEw" }
- Autorização de Requisição
- Método:
GET
- URL:
http://localhost:3000/some_protected_route
- Headers:
Authorization
:Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJleHAiOjE2MTk3NTg4MDB9.tC9omCmt5rmn-ZzA5DUnI8bkL9GpZZKnPipKv2vHBEw
Testando com curl
Realizar Login
curl -X POST -H "Content-Type: application/json" -d '{"email":"[email protected]","password":"password"}' http://localhost:3000/auth/login
Autorização de Requisição
curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJleHAiOjE2MTk3NTg4MDB9.tC9omCmt5rmn-ZzA5DUnI8bkL9GpZZKnPipKv2vHBEw" http://localhost:3000/some_protected_route
Conclusão
Neste artigo, exploramos o conceito de JWT, suas partes (Header, Payload, Signature), vantagens de uso e como implementar JWT em uma aplicação Ruby on Rails para autenticação de usuários. Com JWT, podemos criar sistemas seguros e eficientes que permitem a troca de informações de maneira segura e escalável.