docs/pt/docs/tutorial/security/simple-oauth2.md MARKDOWN 290 lines View on github.com → Search inside
1# Simples OAuth2 com senha e Bearer { #simple-oauth2-with-password-and-bearer }23Agora vamos construir a partir do capítulo anterior e adicionar as partes que faltam para ter um fluxo de segurança completo.45## Obtenha o `username` e a `password` { #get-the-username-and-password }67Vamos usar os utilitários de segurança da **FastAPI** para obter o `username` e a `password`.89OAuth2 especifica que, ao usar o "fluxo de senha" (que estamos usando), o cliente/usuário deve enviar os campos `username` e `password` como dados do formulário.1011E a especificação diz que os campos devem ser nomeados assim. Portanto, `user-name` ou `email` não funcionariam.1213Mas não se preocupe, você pode mostrá-lo como quiser aos usuários finais no frontend.1415E seus modelos de banco de dados podem usar qualquer outro nome que você desejar.1617Mas para a *operação de rota* de login, precisamos usar esses nomes para serem compatíveis com a especificação (e poder, por exemplo, usar o sistema integrado de documentação da API).1819A especificação também afirma que o `username` e a `password` devem ser enviados como dados de formulário (portanto, não há JSON aqui).2021### `scope` { #scope }2223A especificação também diz que o cliente pode enviar outro campo de formulário "`scope`".2425O nome do campo do formulário é `scope` (no singular), mas na verdade é uma longa string com "escopos" separados por espaços.2627Cada “scope” é apenas uma string (sem espaços).2829Normalmente são usados para declarar permissões de segurança específicas, por exemplo:3031* `users:read` ou `users:write` são exemplos comuns.32* `instagram_basic` é usado pelo Facebook / Instagram.33* `https://www.googleapis.com/auth/drive` é usado pelo Google.3435/// note | Nota3637No OAuth2, um "scope" é apenas uma string que declara uma permissão específica necessária.3839Não importa se tem outros caracteres como `:` ou se é uma URL.4041Esses detalhes são específicos da implementação.4243Para OAuth2 são apenas strings.4445///4647## Código para conseguir o `username` e a `password` { #code-to-get-the-username-and-password }4849Agora vamos usar os utilitários fornecidos pelo **FastAPI** para lidar com isso.5051### `OAuth2PasswordRequestForm` { #oauth2passwordrequestform }5253Primeiro, importe `OAuth2PasswordRequestForm` e use-o como uma dependência com `Depends` na *operação de rota* para `/token`:5455{* ../../docs_src/security/tutorial003_an_py310.py hl[4,78] *}5657`OAuth2PasswordRequestForm` é uma dependência de classe que declara um corpo de formulário com:5859* O `username`.60* A `password`.61* Um campo `scope` opcional como uma string grande, composta de strings separadas por espaços.62* Um `grant_type` opcional.6364/// tip | Dica6566A especificação OAuth2 na verdade *requer* um campo `grant_type` com um valor fixo de `password`, mas `OAuth2PasswordRequestForm` não o impõe.6768Se você precisar aplicá-lo, use `OAuth2PasswordRequestFormStrict` em vez de `OAuth2PasswordRequestForm`.6970///7172* Um `client_id` opcional (não precisamos dele em nosso exemplo).73* Um `client_secret` opcional (não precisamos dele em nosso exemplo).7475/// note | Nota7677O `OAuth2PasswordRequestForm` não é uma classe especial para **FastAPI** como é `OAuth2PasswordBearer`.7879`OAuth2PasswordBearer` faz com que **FastAPI** saiba que é um esquema de segurança. Portanto, é adicionado dessa forma ao OpenAPI.8081Mas `OAuth2PasswordRequestForm` é apenas uma dependência de classe que você mesmo poderia ter escrito ou poderia ter declarado os parâmetros de `Form` diretamente.8283Mas como é um caso de uso comum, ele é fornecido diretamente pelo **FastAPI**, apenas para facilitar.8485///8687### Use os dados do formulário { #use-the-form-data }8889/// tip | Dica9091A instância da classe de dependência `OAuth2PasswordRequestForm` não terá um atributo `scope` com a string longa separada por espaços, em vez disso, terá um atributo `scopes` com a lista real de strings para cada escopo enviado.9293Não estamos usando `scopes` neste exemplo, mas a funcionalidade está disponível se você precisar.9495///9697Agora, obtenha os dados do usuário do banco de dados (falso), usando o `username` do campo do formulário.9899Se não existir tal usuário, retornaremos um erro dizendo "Incorrect username or password".100101Para o erro, usamos a exceção `HTTPException`:102103{* ../../docs_src/security/tutorial003_an_py310.py hl[3,79:81] *}104105### Confira a senha { #check-the-password }106107Neste ponto temos os dados do usuário do nosso banco de dados, mas não verificamos a senha.108109Vamos colocar esses dados primeiro no modelo `UserInDB` do Pydantic.110111Você nunca deveria salvar senhas em texto simples, portanto, usaremos o sistema (falso) de hashing de senhas.112113Se as senhas não corresponderem, retornaremos o mesmo erro.114115#### Hashing de senha { #password-hashing }116117"Hashing" significa: converter algum conteúdo (uma senha neste caso) em uma sequência de bytes (apenas uma string) que parece algo sem sentido.118119Sempre que você passa exatamente o mesmo conteúdo (exatamente a mesma senha), você obtém exatamente a mesma sequência aleatória de caracteres.120121Mas você não pode converter a sequência aleatória de caracteres de volta para a senha.122123##### Por que usar hashing de senha { #why-use-password-hashing }124125Se o seu banco de dados for roubado, o ladrão não terá as senhas em texto simples dos seus usuários, apenas os hashes.126127Assim, o ladrão não poderá tentar usar essas mesmas senhas em outro sistema (como muitos usuários usam a mesma senha em todos os lugares, isso seria perigoso).128129{* ../../docs_src/security/tutorial003_an_py310.py hl[82:85] *}130131#### Sobre `**user_dict` { #about-user-dict }132133`UserInDB(**user_dict)` significa:134135*Passe as chaves e valores de `user_dict` diretamente como argumentos de valor-chave, equivalente a:*136137```Python138UserInDB(139    username = user_dict["username"],140    email = user_dict["email"],141    full_name = user_dict["full_name"],142    disabled = user_dict["disabled"],143    hashed_password = user_dict["hashed_password"],144)145```146147/// note | Nota148149Para uma explicação mais completa de `**user_dict`, verifique [a documentação para **Extra Models**](../extra-models.md#about-user-in-model-dump).150151///152153## Retorne o token { #return-the-token }154155A resposta do endpoint `token` deve ser um objeto JSON.156157Deve ter um `token_type`. No nosso caso, como estamos usando tokens "Bearer", o tipo de token deve ser "`bearer`".158159E deve ter um `access_token`, com uma string contendo nosso token de acesso.160161Para este exemplo simples, seremos completamente inseguros e retornaremos o mesmo `username` do token.162163/// tip | Dica164165No próximo capítulo, você verá uma implementação realmente segura, com hash de senha e tokens <abbr title="JSON Web Tokens">JWT</abbr>.166167Mas, por enquanto, vamos nos concentrar nos detalhes específicos de que precisamos.168169///170171{* ../../docs_src/security/tutorial003_an_py310.py hl[87] *}172173/// tip | Dica174175Pela especificação, você deveria retornar um JSON com um `access_token` e um `token_type`, o mesmo que neste exemplo.176177Isso é algo que você mesmo deve fazer em seu código e certifique-se de usar essas chaves JSON.178179É quase a única coisa que você deve se lembrar de fazer corretamente, para estar em conformidade com as especificações.180181De resto, **FastAPI** cuida disso para você.182183///184185## Atualize as dependências { #update-the-dependencies }186187Agora vamos atualizar nossas dependências.188189Queremos obter o `current_user` *somente* se este usuário estiver ativo.190191Portanto, criamos uma dependência adicional `get_current_active_user` que por sua vez usa `get_current_user` como dependência.192193Ambas as dependências retornarão apenas um erro HTTP se o usuário não existir ou se estiver inativo.194195Portanto, em nosso endpoint, só obteremos um usuário se o usuário existir, tiver sido autenticado corretamente e estiver ativo:196197{* ../../docs_src/security/tutorial003_an_py310.py hl[58:66,69:74,94] *}198199/// note | Nota200201O cabeçalho adicional `WWW-Authenticate` com valor `Bearer` que estamos retornando aqui também faz parte da especificação.202203Qualquer código de status HTTP (erro) 401 "UNAUTHORIZED" também deve retornar um cabeçalho `WWW-Authenticate`.204205No caso de tokens ao portador (nosso caso), o valor desse cabeçalho deve ser `Bearer`.206207Na verdade, você pode pular esse cabeçalho extra e ainda funcionaria.208209Mas é fornecido aqui para estar em conformidade com as especificações.210211Além disso, pode haver ferramentas que esperam e usam isso (agora ou no futuro) e que podem ser úteis para você ou seus usuários, agora ou no futuro.212213Esse é o benefício dos padrões...214215///216217## Veja em ação { #see-it-in-action }218219Abra a documentação interativa: [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).220221### Autentique-se { #authenticate }222223Clique no botão "Authorize".224225Use as credenciais:226227User: `johndoe`228229Password: `secret`230231<img src="/img/tutorial/security/image04.png">232233Após autenticar no sistema, você verá assim:234235<img src="/img/tutorial/security/image05.png">236237### Obtenha seus próprios dados de usuário { #get-your-own-user-data }238239Agora use a operação `GET` com o caminho `/users/me`.240241Você obterá os dados do seu usuário, como:242243```JSON244{245  "username": "johndoe",246  "email": "johndoe@example.com",247  "full_name": "John Doe",248  "disabled": false,249  "hashed_password": "fakehashedsecret"250}251```252253<img src="/img/tutorial/security/image06.png">254255Se você clicar no ícone de cadeado, sair e tentar a mesma operação novamente, receberá um erro HTTP 401 de:256257```JSON258{259  "detail": "Not authenticated"260}261```262263### Usuário inativo { #inactive-user }264265Agora tente com um usuário inativo, autentique-se com:266267User: `alice`268269Password: `secret2`270271E tente usar a operação `GET` com o caminho `/users/me`.272273Você receberá um erro "Usuário inativo", como:274275```JSON276{277  "detail": "Inactive user"278}279```280281## Recapitulando { #recap }282283Agora você tem as ferramentas para implementar um sistema de segurança completo baseado em `username` e `password` para sua API.284285Usando essas ferramentas, você pode tornar o sistema de segurança compatível com qualquer banco de dados e com qualquer usuário ou modelo de dados.286287O único detalhe que falta é que ainda não é realmente "seguro".288289No próximo capítulo você verá como usar uma biblioteca de hashing de senha segura e tokens <abbr title="JSON Web Tokens">JWT</abbr>.

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.

Generated by searchcode.com · powered by code_get_file + code_get_findings