Movatterモバイル変換


[0]ホーム

URL:


Ir para o conteúdo
Join theFastAPI Cloud waiting list 🚀
Follow@fastapi onX (Twitter) to stay updated
FollowFastAPI onLinkedIn to stay updated
Subscribe to theFastAPI and friends newsletter 🎉
sponsor
sponsor
sponsor
sponsor
sponsor
sponsor
sponsor
sponsor
sponsor
sponsor
sponsor

HTTP Basic Auth

🌐 Tradução por IA e humanos

Esta tradução foi feita por IA orientada por humanos. 🤝

Ela pode conter erros de interpretação do significado original ou soar pouco natural, etc. 🤖

Você pode melhorar esta traduçãoajudando-nos a orientar melhor o LLM de IA.

Versão em inglês

Para os casos mais simples, você pode utilizar o HTTP Basic Auth.

No HTTP Basic Auth, a aplicação espera um cabeçalho que contém um usuário e uma senha.

Caso ela não receba, ela retorna um erro HTTP 401 "Unauthorized".

E retorna um cabeçalhoWWW-Authenticate com o valorBasic, e um parâmetro opcionalrealm.

Isso sinaliza ao navegador para mostrar o prompt integrado para um usuário e senha.

Então, quando você digitar o usuário e senha, o navegador os envia automaticamente no cabeçalho.

HTTP Basic Auth Simples

  • ImporteHTTPBasic eHTTPBasicCredentials.
  • Crie um "esquemasecurity" utilizandoHTTPBasic.
  • Utilize osecurity com uma dependência em suaoperação de rota.
  • Isso retorna um objeto do tipoHTTPBasicCredentials:
    • Isto contém ousername e opassword enviado.
fromtypingimportAnnotatedfromfastapiimportDepends,FastAPIfromfastapi.securityimportHTTPBasic,HTTPBasicCredentialsapp=FastAPI()security=HTTPBasic()@app.get("/users/me")defread_current_user(credentials:Annotated[HTTPBasicCredentials,Depends(security)]):return{"username":credentials.username,"password":credentials.password}
🤓 Other versions and variants

Tip

Prefer to use theAnnotated version if possible.

fromfastapiimportDepends,FastAPIfromfastapi.securityimportHTTPBasic,HTTPBasicCredentialsapp=FastAPI()security=HTTPBasic()@app.get("/users/me")defread_current_user(credentials:HTTPBasicCredentials=Depends(security)):return{"username":credentials.username,"password":credentials.password}

Quando você tentar abrir a URL pela primeira vez (ou clicar no botão "Executar" na documentação) o navegador vai pedir pelo seu usuário e senha:

Verifique o usuário

Aqui está um exemplo mais completo.

Utilize uma dependência para verificar se o usuário e a senha estão corretos.

Para isso, utilize o módulo padrão do Pythonsecrets para verificar o usuário e senha.

Osecrets.compare_digest() necessita receberbytes oustr que possuem apenas caracteres ASCII (os em inglês). Isso significa que não funcionaria com caracteres como oá, como emSebastián.

Para lidar com isso, primeiramente nós convertemos ousername e opassword parabytes, codificando-os com UTF-8.

Então nós podemos utilizar osecrets.compare_digest() para garantir que ocredentials.username é"stanleyjobson", e que ocredentials.password é"swordfish".

importsecretsfromtypingimportAnnotatedfromfastapiimportDepends,FastAPI,HTTPException,statusfromfastapi.securityimportHTTPBasic,HTTPBasicCredentialsapp=FastAPI()security=HTTPBasic()defget_current_username(credentials:Annotated[HTTPBasicCredentials,Depends(security)],):current_username_bytes=credentials.username.encode("utf8")correct_username_bytes=b"stanleyjobson"is_correct_username=secrets.compare_digest(current_username_bytes,correct_username_bytes)current_password_bytes=credentials.password.encode("utf8")correct_password_bytes=b"swordfish"is_correct_password=secrets.compare_digest(current_password_bytes,correct_password_bytes)ifnot(is_correct_usernameandis_correct_password):raiseHTTPException(status_code=status.HTTP_401_UNAUTHORIZED,detail="Incorrect username or password",headers={"WWW-Authenticate":"Basic"},)returncredentials.username@app.get("/users/me")defread_current_user(username:Annotated[str,Depends(get_current_username)]):return{"username":username}
🤓 Other versions and variants

Tip

Prefer to use theAnnotated version if possible.

importsecretsfromfastapiimportDepends,FastAPI,HTTPException,statusfromfastapi.securityimportHTTPBasic,HTTPBasicCredentialsapp=FastAPI()security=HTTPBasic()defget_current_username(credentials:HTTPBasicCredentials=Depends(security)):current_username_bytes=credentials.username.encode("utf8")correct_username_bytes=b"stanleyjobson"is_correct_username=secrets.compare_digest(current_username_bytes,correct_username_bytes)current_password_bytes=credentials.password.encode("utf8")correct_password_bytes=b"swordfish"is_correct_password=secrets.compare_digest(current_password_bytes,correct_password_bytes)ifnot(is_correct_usernameandis_correct_password):raiseHTTPException(status_code=status.HTTP_401_UNAUTHORIZED,detail="Incorrect username or password",headers={"WWW-Authenticate":"Basic"},)returncredentials.username@app.get("/users/me")defread_current_user(username:str=Depends(get_current_username)):return{"username":username}

Isso seria parecido com:

ifnot(credentials.username=="stanleyjobson")ornot(credentials.password=="swordfish"):# Return some error...

Porém, ao utilizar osecrets.compare_digest(), isso estará seguro contra um tipo de ataque chamado "timing attacks" (ataques de temporização).

Ataques de Temporização

Mas o que é um "timing attack" (ataque de temporização)?

Vamos imaginar que alguns invasores estão tentando adivinhar o usuário e a senha.

E eles enviam uma requisição com um usuáriojohndoe e uma senhalove123.

Então o código Python em sua aplicação seria equivalente a algo como:

if"johndoe"=="stanleyjobson"and"love123"=="swordfish":...

Mas no exato momento que o Python compara o primeiroj emjohndoe contra o primeiros emstanleyjobson, ele retornaráFalse, porque ele já sabe que aquelas duas strings não são a mesma, pensando que "não existe a necessidade de desperdiçar mais poder computacional comparando o resto das letras". E a sua aplicação dirá "Usuário ou senha incorretos".

Então os invasores vão tentar com o usuáriostanleyjobsox e a senhalove123.

E a sua aplicação faz algo como:

if"stanleyjobsox"=="stanleyjobson"and"love123"=="swordfish":...

O Python terá que comparar todo ostanleyjobso tanto emstanleyjobsox como emstanleyjobson antes de perceber que as strings não são a mesma. Então isso levará alguns microssegundos a mais para retornar "Usuário ou senha incorretos".

O tempo para responder ajuda os invasores

Neste ponto, ao perceber que o servidor demorou alguns microssegundos a mais para enviar o retorno "Usuário ou senha incorretos", os invasores irão saber que eles acertaramalguma coisa, algumas das letras iniciais estavam certas.

E eles podem tentar de novo sabendo que provavelmente é algo mais parecido comstanleyjobsox do que comjohndoe.

Um ataque "profissional"

Claro, os invasores não tentariam tudo isso de forma manual, eles escreveriam um programa para fazer isso, possivelmente com milhares ou milhões de testes por segundo. E obteriam apenas uma letra a mais por vez.

Mas fazendo isso, em alguns minutos ou horas os invasores teriam adivinhado o usuário e senha corretos, com a "ajuda" da nossa aplicação, apenas usando o tempo levado para responder.

Corrija com osecrets.compare_digest()

Mas em nosso código já estamos utilizando osecrets.compare_digest().

Resumindo, levará o mesmo tempo para compararstanleyjobsox comstanleyjobson do que compararjohndoe comstanleyjobson. E o mesmo para a senha.

Deste modo, ao utilizarsecrets.compare_digest() no código de sua aplicação, ela estará a salvo contra toda essa gama de ataques de segurança.

Retorne o erro

Após detectar que as credenciais estão incorretas, retorne umHTTPException com o status 401 (o mesmo retornado quando nenhuma credencial foi informada) e adicione o cabeçalhoWWW-Authenticate para fazer com que o navegador mostre o prompt de login novamente:

importsecretsfromtypingimportAnnotatedfromfastapiimportDepends,FastAPI,HTTPException,statusfromfastapi.securityimportHTTPBasic,HTTPBasicCredentialsapp=FastAPI()security=HTTPBasic()defget_current_username(credentials:Annotated[HTTPBasicCredentials,Depends(security)],):current_username_bytes=credentials.username.encode("utf8")correct_username_bytes=b"stanleyjobson"is_correct_username=secrets.compare_digest(current_username_bytes,correct_username_bytes)current_password_bytes=credentials.password.encode("utf8")correct_password_bytes=b"swordfish"is_correct_password=secrets.compare_digest(current_password_bytes,correct_password_bytes)ifnot(is_correct_usernameandis_correct_password):raiseHTTPException(status_code=status.HTTP_401_UNAUTHORIZED,detail="Incorrect username or password",headers={"WWW-Authenticate":"Basic"},)returncredentials.username@app.get("/users/me")defread_current_user(username:Annotated[str,Depends(get_current_username)]):return{"username":username}
🤓 Other versions and variants

Tip

Prefer to use theAnnotated version if possible.

importsecretsfromfastapiimportDepends,FastAPI,HTTPException,statusfromfastapi.securityimportHTTPBasic,HTTPBasicCredentialsapp=FastAPI()security=HTTPBasic()defget_current_username(credentials:HTTPBasicCredentials=Depends(security)):current_username_bytes=credentials.username.encode("utf8")correct_username_bytes=b"stanleyjobson"is_correct_username=secrets.compare_digest(current_username_bytes,correct_username_bytes)current_password_bytes=credentials.password.encode("utf8")correct_password_bytes=b"swordfish"is_correct_password=secrets.compare_digest(current_password_bytes,correct_password_bytes)ifnot(is_correct_usernameandis_correct_password):raiseHTTPException(status_code=status.HTTP_401_UNAUTHORIZED,detail="Incorrect username or password",headers={"WWW-Authenticate":"Basic"},)returncredentials.username@app.get("/users/me")defread_current_user(username:str=Depends(get_current_username)):return{"username":username}

[8]ページ先頭

©2009-2026 Movatter.jp