A implementação de OAuth2 com tokens JWT (JSON Web Tokens) tem se tornado uma prática essencial para garantir a segurança em aplicativos modernos. Utilizando tokens em vez de credenciais, esse método oferece uma abordagem mais segura e eficiente para autenticar usuários. Neste capítulo, vamos explorar como integrar OAuth2 com JWT para melhorar a segurança da autenticação em uma aplicação SaaS.

Primeiramente, é importante garantir que você tenha todas as dependências necessárias instaladas. Caso ainda não tenha instalado os pacotes do arquivo requirements.txt, basta rodar o seguinte comando:

bash
$ pip install python-jose[cryptography]

Vamos também utilizar a tabela de usuários que foi configurada no capítulo anterior para o cadastro de novos usuários. Portanto, é necessário garantir que a base de dados esteja configurada corretamente antes de iniciar.

A integração do JWT envolve a criação de funções para autenticar o usuário, gerar e decodificar tokens de acesso, e proteger endpoints utilizando esses tokens.

Autenticando o Usuário

O primeiro passo é definir uma função que valide o usuário com base no nome de usuário ou no e-mail. Para isso, no arquivo security.py, criamos a seguinte função de autenticação:

python
from sqlalchemy.orm import Session from models import User from email_validator import validate_email, EmailNotValidError from operations import pwd_context def authenticate_user(session: Session, username_or_email: str, password: str) -> User | None: try: validate_email(username_or_email) query_filter = User.email except EmailNotValidError: query_filter = User.username user = session.query(User).filter(query_filter == username_or_email).first()
if not user or not pwd_context.verify(password, user.hashed_password):
return None return user

Essa função tenta validar se o campo fornecido é um e-mail ou um nome de usuário e, em seguida, procura o usuário na base de dados. Se o usuário for encontrado e a senha for verificada, ele é autenticado com sucesso.

Gerando e Decodificando o Token de Acesso

Para criar o token JWT, definimos um segredo, o algoritmo de codificação e o tempo de expiração. No exemplo, o tempo de expiração é de 30 minutos:

python
SECRET_KEY = "a_very_secret_key" ALGORITHM = "HS256" ACCESS_TOKEN_EXPIRE_MINUTES = 30

A função para criar o token de acesso é a seguinte:

python
from jose import jwt
from datetime import datetime, timedelta def create_access_token(data: dict) -> str: to_encode = data.copy() expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) to_encode.update({"exp": expire}) encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) return encoded_jwt

Ao criar o token, é adicionada uma data de expiração para garantir que o token não seja válido indefinidamente.

Para decodificar o token e recuperar as informações do usuário, utilizamos a seguinte função:

python
from jose import JWTError
def decode_access_token(token: str, session: Session) -> User | None: try: payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) username: str = payload.get("sub") except JWTError: return None if not username: return None user = get_user(session, username) return user

Endpoints para Gerenciamento do Token

Após definir as funções para criar e decodificar o token, criamos um endpoint para solicitar o token. Este endpoint receberá o nome de usuário e a senha do usuário e retornará o token de acesso:

python
from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordRequestForm router = APIRouter() class Token(BaseModel): access_token: str token_type: str @router.post("/token", response_model=Token) def get_user_access_token(form_data: OAuth2PasswordRequestForm = Depends(), session: Session = Depends(get_session)): user = authenticate_user(session, form_data.username, form_data.password) if not user: raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Incorrect username or password") access_token = create_access_token(data={"sub": user.username})
return {"access_token": access_token, "token_type": "bearer"}

Esse endpoint, ao receber uma requisição POST com as credenciais do usuário, validará a autenticidade e, se bem-sucedido, retornará um token JWT.

Protegendo Endpoints com JWT

Para proteger endpoints e garantir que apenas usuários autenticados possam acessá-los, utilizamos a classe OAuth2PasswordBearer do FastAPI. Isso permite que o token de acesso seja passado como parte da solicitação, geralmente no cabeçalho de autorização. Por exemplo, para um endpoint que retorna as informações do usuário:

python
from fastapi.security import OAuth2PasswordBearer
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") @router.get("/users/me") def read_user_me(token: str = Depends(oauth2_scheme), session: Session = Depends(get_session)): user = decode_access_token(token, session) if not user: raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="User not authorized") return {"description": f"{user.username} authorized"}

Esse endpoint exige que o token seja enviado, e o sistema valida o token antes de retornar as informações do usuário.

Conclusão

Integrar OAuth2 com JWT é uma excelente maneira de garantir que apenas usuários autenticados possam acessar informações sensíveis em sua aplicação. Esse processo melhora a segurança ao substituir credenciais tradicionais por tokens, o que é mais seguro e flexível. Ao implementar essa abordagem, você estará em conformidade com as práticas modernas de segurança e terá um sistema de autenticação robusto para proteger sua aplicação SaaS.

Além disso, é importante lembrar que, ao utilizar OAuth2 e JWT, você deve implementar mecanismos de expiração e renovação de tokens para evitar problemas de segurança a longo prazo. A implementação de uma estratégia de revogação de tokens e a utilização de HTTPS para garantir que a comunicação entre cliente e servidor seja segura também são fundamentais para proteger as credenciais do usuário.

Como Organizar e Configurar um Projeto FastAPI: Do Início ao Controle de Versão

Ao iniciar um novo projeto de desenvolvimento com FastAPI, a configuração adequada do ambiente de trabalho e o controle de versão são passos essenciais para garantir a escalabilidade, a organização e a produtividade ao longo de toda a jornada do desenvolvimento. Esta seção aborda como personalizar seu ambiente de desenvolvimento, configurar o Git para versionamento e dar os primeiros passos com o FastAPI, mantendo boas práticas de estruturação do código e organização do projeto.

Personalizando seu Ambiente de Desenvolvimento

Antes de mergulhar no código, é importante que o ambiente de desenvolvimento seja ajustado de acordo com suas preferências e fluxo de trabalho. Personalizar seu IDE (Ambiente de Desenvolvimento Integrado) é uma maneira simples de aumentar a produtividade e o conforto enquanto codifica. Isso pode incluir ajustes no tema do editor, nas teclas de atalho e nas configurações gerais, para que o ambiente se torne mais agradável e intuitivo para o seu uso diário.

Configurando o Git e GitHub

O controle de versão é uma prática fundamental no desenvolvimento de software, permitindo o rastreamento das alterações no código, facilitando a colaboração com outros desenvolvedores e garantindo a integridade do histórico do projeto. Git, em conjunto com GitHub, é uma poderosa ferramenta que facilita o gerenciamento e a integração do código.

Após instalar o Git em seu sistema, o primeiro passo é configurar o Git com seu nome de usuário e e-mail. Isso é feito por meio de comandos simples no terminal:

bash
$ git config --global user.name "Seu Nome" $ git config --global user.email "[email protected]"

Em seguida, crie um repositório no GitHub para armazenar os exemplos de código e outras referências do seu projeto. Se ainda não possui uma conta no GitHub, acesse github.com e faça o cadastro.

A criação de um projeto FastAPI começa com uma estrutura de pastas bem organizada, o que facilita a navegação, o depuramento e a colaboração. Para isso, siga os passos abaixo para configurar o projeto:

  1. Crie uma pasta de projeto chamada fastapi_start e acesse-a pelo terminal.

  2. Inicialize um ambiente virtual para gerenciar as dependências do projeto:

bash
$ python -m venv .venv
  1. Ative o ambiente virtual. No caso do macOS ou Linux:

bash
$ source .venv/bin/activate

No Windows, o comando será:

bash
$ .venv\Scripts\activate
  1. Com o ambiente ativado, instale o FastAPI e o servidor Uvicorn:

bash
$ pip install fastapi uvicorn
  1. Crie um arquivo main.py e comece a escrever o código inicial da aplicação FastAPI:

python
from fastapi import FastAPI app = FastAPI() @app.get("/") def read_root(): return {"Hello": "World"}

Esse é o esqueleto básico de uma aplicação FastAPI. Para adicionar controle de versão ao seu projeto, inicie um repositório Git no diretório raiz do projeto com o comando:

bash
$ git init

Em seguida, crie um arquivo .gitignore para especificar quais arquivos não devem ser rastreados, como pastas de cache e o próprio ambiente virtual. Adicione seus arquivos ao repositório com os seguintes comandos:

bash
$ git add . $ git commit -m "Commit inicial"

Organizando o Projeto FastAPI

Uma estrutura de projeto bem organizada é a chave para a manutenção e evolução de uma aplicação. Embora não haja uma estrutura única e definitiva para todos os projetos FastAPI, uma abordagem comum e eficaz é dividir o projeto em diretórios claros e bem definidos. Isso não só melhora a legibilidade do código, mas também facilita a colaboração e a escalabilidade do sistema.

  1. /src: Este diretório contém o código principal da aplicação. Dentro de /src, é comum ter subdiretórios para diferentes módulos da aplicação, como models para os modelos de banco de dados, routes para as rotas do FastAPI e services para a lógica de negócios.

  2. /tests: Manter os testes separados do código da aplicação é uma prática recomendada. Isso facilita o gerenciamento dos testes e garante que o código de produção não seja misturado com código de teste.

  3. /docs: Documentação é fundamental em qualquer projeto. Criar uma pasta dedicada à documentação ajuda a manter as instruções claras e organizadas, seja para uso interno ou para que outros desenvolvedores possam compreender como utilizar a API.

Fundamentos do FastAPI

O FastAPI é um framework moderno e rápido para o desenvolvimento de APIs com Python, que utiliza os recursos dos tipos de dados do Python para gerar código robusto e bem documentado. Algumas das características que tornam o FastAPI uma escolha popular para desenvolvedores incluem:

  • Velocidade: O FastAPI é um dos frameworks mais rápidos para a criação de APIs em Python, graças ao Starlette (para o desenvolvimento web) e ao Pydantic (para o manuseio de dados).

  • Facilidade de uso: O FastAPI foi projetado para ser fácil de usar, com uma codificação intuitiva que acelera o tempo de desenvolvimento.

  • Documentação automática: Uma das características mais interessantes do FastAPI é a geração automática da documentação da API. Isso facilita não apenas o desenvolvimento, mas também a utilização da API por outros desenvolvedores.

Programação Assíncrona

O FastAPI se destaca por sua capacidade de utilizar a programação assíncrona de forma eficiente. A programação assíncrona permite que o aplicativo lide com múltiplas requisições ao mesmo tempo, sem bloquear a execução de outras tarefas. Isso torna a aplicação mais eficiente e escalável, especialmente quando se trata de lidar com entradas e saídas (I/O) lentas, como interações com bancos de dados ou chamadas de rede.

Ao utilizar o FastAPI, você pode definir funções assíncronas utilizando a sintaxe async/await para garantir que o sistema consiga gerenciar várias requisições simultaneamente, sem comprometer o desempenho. Por exemplo, um endpoint simples pode ser definido de forma assíncrona da seguinte maneira:

python
@app.get("/async") async def async_route(): return {"message": "Esta é uma resposta assíncrona!"}

Essa abordagem permite que a aplicação continue processando outras requisições enquanto aguarda a conclusão de tarefas de I/O, como consultas a banco de dados.

Conclusão

Com uma configuração adequada do Git, uma estrutura organizada e o uso de boas práticas de programação assíncrona, o FastAPI oferece uma base sólida para o desenvolvimento de APIs modernas e eficientes. O framework é projetado para ser rápido, fácil de usar e altamente escalável, tornando-o uma escolha ideal para desenvolvedores que buscam uma solução de alto desempenho e baixa latência para suas aplicações web.