mirror of https://github.com/tiangolo/fastapi.git
🌐 Add Portuguese translation for `docs/pt/docs/tutorial/security/oauth2-jwt.md` (#13205)
This commit is contained in:
parent
2612fa3e9d
commit
16199c4a13
|
|
@ -0,0 +1,274 @@
|
|||
# OAuth2 com Senha (e hashing), Bearer com tokens JWT
|
||||
|
||||
Agora que temos todo o fluxo de segurança, vamos tornar a aplicação realmente segura, usando tokens <abbr title="JSON Web Tokens">JWT</abbr> e hashing de senhas seguras.
|
||||
|
||||
Este código é algo que você pode realmente usar na sua aplicação, salvar os hashes das senhas no seu banco de dados, etc.
|
||||
|
||||
Vamos começar de onde paramos no capítulo anterior e incrementá-lo.
|
||||
|
||||
## Sobre o JWT
|
||||
|
||||
JWT significa "JSON Web Tokens".
|
||||
|
||||
É um padrão para codificar um objeto JSON em uma string longa e densa sem espaços. Ele se parece com isso:
|
||||
|
||||
```
|
||||
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
|
||||
```
|
||||
|
||||
Ele não é criptografado, então qualquer pessoa pode recuperar as informações do seu conteúdo.
|
||||
|
||||
Mas ele é assinado. Assim, quando você recebe um token que você emitiu, você pode verificar que foi realmente você quem o emitiu.
|
||||
|
||||
Dessa forma, você pode criar um token com um prazo de expiração, digamos, de 1 semana. E então, quando o usuário voltar no dia seguinte com o token, você sabe que ele ainda está logado no seu sistema.
|
||||
|
||||
Depois de uma semana, o token expirará e o usuário não estará autorizado, precisando fazer login novamente para obter um novo token. E se o usuário (ou uma terceira parte) tentar modificar o token para alterar a expiração, você seria capaz de descobrir isso, pois as assinaturas não iriam corresponder.
|
||||
|
||||
Se você quiser brincar com tokens JWT e ver como eles funcionam, visite <a href="https://jwt.io/" class="external-link" target="_blank">https://jwt.io</a>.
|
||||
|
||||
## Instalar `PyJWT`
|
||||
|
||||
Nós precisamos instalar o `PyJWT` para criar e verificar os tokens JWT em Python.
|
||||
|
||||
Certifique-se de criar um [ambiente virtual](../../virtual-environments.md){.internal-link target=_blank}, ativá-lo e então instalar o `pyjwt`:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install pyjwt
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
/// info | Informação
|
||||
|
||||
Se você pretente utilizar algoritmos de assinatura digital como o RSA ou o ECDSA, você deve instalar a dependência da biblioteca de criptografia `pyjwt[crypto]`.
|
||||
|
||||
Você pode ler mais sobre isso na <a href="https://pyjwt.readthedocs.io/en/latest/installation.html" class="external-link" target="_blank">documentação de instalação do PyJWT</a>.
|
||||
|
||||
///
|
||||
|
||||
## Hashing de senhas
|
||||
|
||||
"Hashing" significa converter algum conteúdo (uma senha neste caso) em uma sequência de bytes (apenas uma string) que parece um monte de caracteres sem sentido.
|
||||
|
||||
Sempre que você passar exatamente o mesmo conteúdo (exatamente a mesma senha), você obterá exatamente o mesmo resultado.
|
||||
|
||||
Mas não é possível converter os caracteres sem sentido de volta para a senha original.
|
||||
|
||||
### Por que usar hashing de senhas
|
||||
|
||||
Se o seu banco de dados for roubado, o invasor não terá as senhas em texto puro dos seus usuários, apenas os hashes.
|
||||
|
||||
Então, o invasor não poderá tentar usar essas senhas em outro sistema (como muitos usuários utilizam a mesma senha em vários lugares, isso seria perigoso).
|
||||
|
||||
## Instalar o `passlib`
|
||||
|
||||
O PassLib é uma excelente biblioteca Python para lidar com hashes de senhas.
|
||||
|
||||
Ele suporta muitos algoritmos de hashing seguros e utilitários para trabalhar com eles.
|
||||
|
||||
O algoritmo recomendado é o "Bcrypt".
|
||||
|
||||
Certifique-se de criar um [ambiente virtual](../../virtual-environments.md){.internal-link target=_blank}, ativá-lo e então instalar o PassLib com Bcrypt:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install "passlib[bcrypt]"
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Com o `passlib`, você poderia até configurá-lo para ser capaz de ler senhas criadas pelo **Django**, um plug-in de segurança do **Flask** ou muitos outros.
|
||||
|
||||
Assim, você poderia, por exemplo, compartilhar os mesmos dados de um aplicativo Django em um banco de dados com um aplicativo FastAPI. Ou migrar gradualmente uma aplicação Django usando o mesmo banco de dados.
|
||||
|
||||
E seus usuários poderiam fazer login tanto pela sua aplicação Django quanto pela sua aplicação **FastAPI**, ao mesmo tempo.
|
||||
|
||||
///
|
||||
|
||||
## Criar o hash e verificar as senhas
|
||||
|
||||
Importe as ferramentas que nós precisamos de `passlib`.
|
||||
|
||||
Crie um "contexto" do PassLib. Este será usado para criar o hash e verificar as senhas.
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
O contexto do PassLib também possui funcionalidades para usar diferentes algoritmos de hashing, incluindo algoritmos antigos que estão obsoletos, apenas para permitir verificá-los, etc.
|
||||
|
||||
Por exemplo, você poderia usá-lo para ler e verificar senhas geradas por outro sistema (como Django), mas criar o hash de novas senhas com um algoritmo diferente, como o Bcrypt.
|
||||
|
||||
E ser compatível com todos eles ao mesmo tempo.
|
||||
|
||||
///
|
||||
|
||||
Crie uma função utilitária para criar o hash de uma senha fornecida pelo usuário.
|
||||
|
||||
E outra função utilitária para verificar se uma senha recebida corresponde ao hash armazenado.
|
||||
|
||||
E outra para autenticar e retornar um usuário.
|
||||
|
||||
{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,56:57,60:61,70:76] *}
|
||||
|
||||
/// note | Nota
|
||||
|
||||
Se você verificar o novo banco de dados (falso) `fake_users_db`, você verá como o hash da senha se parece agora: `"$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW"`.
|
||||
|
||||
///
|
||||
|
||||
## Manipular tokens JWT
|
||||
|
||||
Importe os módulos instalados.
|
||||
|
||||
Crie uma chave secreta aleatória que será usada para assinar os tokens JWT.
|
||||
|
||||
Para gerar uma chave secreta aleatória e segura, use o comando:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ openssl rand -hex 32
|
||||
|
||||
09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
E copie a saída para a variável `SECRET_KEY` (não use a do exemplo).
|
||||
|
||||
Crie uma variável `ALGORITHM` com o algoritmo usado para assinar o token JWT e defina como `"HS256"`.
|
||||
|
||||
Crie uma variável para a expiração do token.
|
||||
|
||||
Defina um modelo Pydantic que será usado no endpoint de token para a resposta.
|
||||
|
||||
Crie uma função utilitária para gerar um novo token de acesso.
|
||||
|
||||
{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,79:87] *}
|
||||
|
||||
## Atualize as dependências
|
||||
|
||||
Atualize `get_current_user` para receber o mesmo token de antes, mas desta vez, usando tokens JWT.
|
||||
|
||||
Decodifique o token recebido, verifique-o e retorne o usuário atual.
|
||||
|
||||
Se o token for inválido, retorne um erro HTTP imediatamente.
|
||||
|
||||
{* ../../docs_src/security/tutorial004_an_py310.py hl[90:107] *}
|
||||
|
||||
## Atualize a *operação de rota* `/token`
|
||||
|
||||
Crie um `timedelta` com o tempo de expiração do token.
|
||||
|
||||
Crie um token de acesso JWT real e o retorne.
|
||||
|
||||
{* ../../docs_src/security/tutorial004_an_py310.py hl[118:133] *}
|
||||
|
||||
### Detalhes técnicos sobre o "sujeito" `sub` do JWT
|
||||
|
||||
A especificação JWT diz que existe uma chave `sub`, com o sujeito do token.
|
||||
|
||||
É opcional usá-la, mas é onde você colocaria a identificação do usuário, então nós estamos usando aqui.
|
||||
|
||||
O JWT pode ser usado para outras coisas além de identificar um usuário e permitir que ele execute operações diretamente na sua API.
|
||||
|
||||
Por exemplo, você poderia identificar um "carro" ou uma "postagem de blog".
|
||||
|
||||
Depois, você poderia adicionar permissões sobre essa entidade, como "dirigir" (para o carro) ou "editar" (para o blog).
|
||||
|
||||
E então, poderia dar esse token JWT para um usuário (ou bot), e ele poderia usá-lo para realizar essas ações (dirigir o carro ou editar o blog) sem sequer precisar ter uma conta, apenas com o token JWT que sua API gerou para isso.
|
||||
|
||||
Usando essas ideias, o JWT pode ser usado para cenários muito mais sofisticados.
|
||||
|
||||
Nesses casos, várias dessas entidades poderiam ter o mesmo ID, digamos `foo` (um usuário `foo`, um carro `foo` e uma postagem de blog `foo`).
|
||||
|
||||
Então, para evitar colisões de ID, ao criar o token JWT para o usuário, você poderia prefixar o valor da chave `sub`, por exemplo, com `username:`. Assim, neste exemplo, o valor de `sub` poderia ser: `username:johndoe`.
|
||||
|
||||
O importante a se lembrar é que a chave `sub` deve ter um identificador único em toda a aplicação e deve ser uma string.
|
||||
|
||||
## Testando
|
||||
|
||||
Execute o servidor e vá para a documentação: <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
|
||||
Você verá a interface de usuário assim:
|
||||
|
||||
<img src="/img/tutorial/security/image07.png">
|
||||
|
||||
Autorize a aplicação da mesma maneira que antes.
|
||||
|
||||
Usando as credenciais:
|
||||
|
||||
Username: `johndoe`
|
||||
Password: `secret`
|
||||
|
||||
/// check | Verifique
|
||||
|
||||
Observe que em nenhuma parte do código está a senha em texto puro "`secret`", nós temos apenas o hash.
|
||||
|
||||
///
|
||||
|
||||
<img src="/img/tutorial/security/image08.png">
|
||||
|
||||
Chame o endpoint `/users/me/`, você receberá o retorno como:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"username": "johndoe",
|
||||
"email": "johndoe@example.com",
|
||||
"full_name": "John Doe",
|
||||
"disabled": false
|
||||
}
|
||||
```
|
||||
|
||||
<img src="/img/tutorial/security/image09.png">
|
||||
|
||||
Se você abrir as ferramentas de desenvolvedor, poderá ver que os dados enviados incluem apenas o token. A senha é enviada apenas na primeira requisição para autenticar o usuário e obter o token de acesso, mas não é enviada nas próximas requisições:
|
||||
|
||||
<img src="/img/tutorial/security/image10.png">
|
||||
|
||||
/// note | Nota
|
||||
|
||||
Perceba que o cabeçalho `Authorization`, com o valor que começa com `Bearer `.
|
||||
|
||||
///
|
||||
|
||||
## Uso avançado com `scopes`
|
||||
|
||||
O OAuth2 tem a noção de "scopes" (escopos).
|
||||
|
||||
Você pode usá-los para adicionar um conjunto específico de permissões a um token JWT.
|
||||
|
||||
Então, você pode dar este token diretamente a um usuário ou a uma terceira parte para interagir com sua API com um conjunto de restrições.
|
||||
|
||||
Você pode aprender como usá-los e como eles são integrados ao **FastAPI** mais adiante no **Guia Avançado do Usuário**.
|
||||
|
||||
|
||||
## Recapitulação
|
||||
|
||||
Com o que você viu até agora, você pode configurar uma aplicação **FastAPI** segura usando padrões como OAuth2 e JWT.
|
||||
|
||||
Em quase qualquer framework, lidar com a segurança se torna rapidamente um assunto bastante complexo.
|
||||
|
||||
Muitos pacotes que simplificam bastante isso precisam fazer muitas concessões com o modelo de dados, o banco de dados e os recursos disponíveis. E alguns desses pacotes que simplificam demais na verdade têm falhas de segurança subjacentes.
|
||||
|
||||
---
|
||||
|
||||
O **FastAPI** não faz nenhuma concessão com nenhum banco de dados, modelo de dados ou ferramenta.
|
||||
|
||||
Ele oferece toda a flexibilidade para você escolher as opções que melhor se ajustam ao seu projeto.
|
||||
|
||||
E você pode usar diretamente muitos pacotes bem mantidos e amplamente utilizados, como `passlib` e `PyJWT`, porque o **FastAPI** não exige mecanismos complexos para integrar pacotes externos.
|
||||
|
||||
Mas ele fornece as ferramentas para simplificar o processo o máximo possível, sem comprometer a flexibilidade, robustez ou segurança.
|
||||
|
||||
E você pode usar e implementar protocolos padrão seguros, como o OAuth2, de uma maneira relativamente simples.
|
||||
|
||||
Você pode aprender mais no **Guia Avançado do Usuário** sobre como usar os "scopes" do OAuth2 para um sistema de permissões mais refinado, seguindo esses mesmos padrões. O OAuth2 com scopes é o mecanismo usado por muitos provedores grandes de autenticação, como o Facebook, Google, GitHub, Microsoft, Twitter, etc. para autorizar aplicativos de terceiros a interagir com suas APIs em nome de seus usuários.
|
||||
Loading…
Reference in New Issue