HTTP Basic Auth¶
🌐 एआई और मनुष्यों द्वारा किया गया अनुवाद
यह अनुवाद मनुष्यों के मार्गदर्शन में एआई द्वारा किया गया है। 🤝
इसमें मूल अर्थ को गलत समझने या अप्राकृतिक लगने आदि जैसी गलतियाँ हो सकती हैं। 🤖
आप हमें एआई LLM को बेहतर मार्गदर्शन करने में मदद करके इस अनुवाद को बेहतर बना सकते हैं।
सबसे सरल मामलों के लिए, आप HTTP Basic Auth का उपयोग कर सकते हैं।
HTTP Basic Auth में, application एक header की अपेक्षा करता है जिसमें username और password होता है।
अगर उसे यह नहीं मिलता, तो यह HTTP 401 "Unauthorized" error लौटाता है।
और WWW-Authenticate header लौटाता है जिसका value Basic होता है, और एक optional realm parameter होता है।
यह browser को username और password के लिए integrated prompt दिखाने को कहता है।
फिर, जब आप वह username और password टाइप करते हैं, तो browser उन्हें header में अपने-आप भेज देता है।
Simple HTTP Basic Auth¶
HTTPBasicऔरHTTPBasicCredentialsimport करें।HTTPBasicका उपयोग करके एक "securityscheme" बनाएँ।- अपने path operation में dependency के साथ उस
securityका उपयोग करें। - यह
HTTPBasicCredentialstype का एक object लौटाता है:- इसमें भेजे गए
usernameऔरpasswordहोते हैं।
- इसमें भेजे गए
from typing import Annotated
from fastapi import Depends, FastAPI
from fastapi.security import HTTPBasic, HTTPBasicCredentials
app = FastAPI()
security = HTTPBasic()
@app.get("/users/me")
def read_current_user(credentials: Annotated[HTTPBasicCredentials, Depends(security)]):
return {"username": credentials.username, "password": credentials.password}
🤓 Other versions and variants
Tip
Prefer to use the Annotated version if possible.
from fastapi import Depends, FastAPI
from fastapi.security import HTTPBasic, HTTPBasicCredentials
app = FastAPI()
security = HTTPBasic()
@app.get("/users/me")
def read_current_user(credentials: HTTPBasicCredentials = Depends(security)):
return {"username": credentials.username, "password": credentials.password}
जब आप पहली बार URL खोलने की कोशिश करते हैं (या docs में "Execute" button पर क्लिक करते हैं), तो browser आपसे आपका username और password पूछेगा:

Username जाँचें¶
यहाँ एक अधिक complete example है।
यह जाँचने के लिए dependency का उपयोग करें कि username और password सही हैं या नहीं।
इसके लिए, username और password जाँचने के लिए Python standard module secrets का उपयोग करें।
secrets.compare_digest() को bytes या ऐसा str लेना होता है जिसमें केवल ASCII characters (English वाले) हों, इसका मतलब है कि यह á जैसे characters के साथ काम नहीं करेगा, जैसे Sebastián में।
इसे handle करने के लिए, हम पहले username और password को UTF-8 से encode करके bytes में convert करते हैं।
फिर हम secrets.compare_digest() का उपयोग करके यह सुनिश्चित कर सकते हैं कि credentials.username "stanleyjobson" है, और credentials.password "swordfish" है।
import secrets
from typing import Annotated
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import HTTPBasic, HTTPBasicCredentials
app = FastAPI()
security = HTTPBasic()
def get_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
)
if not (is_correct_username and is_correct_password):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Basic"},
)
return credentials.username
@app.get("/users/me")
def read_current_user(username: Annotated[str, Depends(get_current_username)]):
return {"username": username}
🤓 Other versions and variants
Tip
Prefer to use the Annotated version if possible.
import secrets
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import HTTPBasic, HTTPBasicCredentials
app = FastAPI()
security = HTTPBasic()
def get_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
)
if not (is_correct_username and is_correct_password):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Basic"},
)
return credentials.username
@app.get("/users/me")
def read_current_user(username: str = Depends(get_current_username)):
return {"username": username}
यह इसके समान होगा:
if not (credentials.username == "stanleyjobson") or not (credentials.password == "swordfish"):
# कोई error लौटाएँ
...
लेकिन secrets.compare_digest() का उपयोग करने से यह "timing attacks" नाम के attacks के एक type के विरुद्ध सुरक्षित रहेगा।
Timing Attacks¶
लेकिन "timing attack" क्या होता है?
मान लीजिए कुछ attackers username और password का अनुमान लगाने की कोशिश कर रहे हैं।
और वे username johndoe और password love123 के साथ एक request भेजते हैं।
तब आपकी application में Python code कुछ इस तरह के बराबर होगा:
if "johndoe" == "stanleyjobson" and "love123" == "swordfish":
...
लेकिन जैसे ही Python johndoe में पहले j की तुलना stanleyjobson में पहले s से करता है, यह False लौटा देगा, क्योंकि उसे पहले से पता है कि ये दोनों strings समान नहीं हैं, यह सोचते हुए कि "बाकी अक्षरों की तुलना करके और computation खर्च करने की जरूरत नहीं है"। और आपकी application कहेगी "Incorrect username or password"।
लेकिन फिर attackers username stanleyjobsox और password love123 के साथ कोशिश करते हैं।
और आपका application code कुछ ऐसा करता है:
if "stanleyjobsox" == "stanleyjobson" and "love123" == "swordfish":
...
Python को यह समझने से पहले कि दोनों strings समान नहीं हैं, stanleyjobsox और stanleyjobson दोनों में पूरे stanleyjobso की तुलना करनी पड़ेगी। इसलिए "Incorrect username or password" का reply वापस देने में कुछ extra microseconds लगेंगे।
जवाब देने में लगा समय attackers की मदद करता है¶
उस समय, यह देखकर कि server ने "Incorrect username or password" response भेजने में कुछ microseconds ज्यादा लिए, attackers जान जाएँगे कि उन्होंने कुछ सही पाया है, शुरुआती अक्षरों में से कुछ सही थे।
और फिर वे यह जानते हुए फिर कोशिश कर सकते हैं कि यह शायद johndoe की तुलना में stanleyjobsox से ज्यादा मिलता-जुलता है।
एक "professional" attack¶
बेशक, attackers यह सब हाथ से नहीं करेंगे, वे इसे करने के लिए एक program लिखेंगे, संभवतः प्रति सेकंड हजारों या लाखों tests के साथ। और उन्हें एक समय में बस एक extra सही अक्षर मिलेगा।
लेकिन ऐसा करते हुए, कुछ minutes या hours में attackers ने हमारी application की "help" से सही username और password का अनुमान लगा लिया होगा, सिर्फ जवाब देने में लगे समय का उपयोग करके।
इसे secrets.compare_digest() से ठीक करें¶
लेकिन हमारे code में हम वास्तव में secrets.compare_digest() का उपयोग कर रहे हैं।
संक्षेप में, stanleyjobsox की तुलना stanleyjobson से करने में उतना ही समय लगेगा जितना johndoe की तुलना stanleyjobson से करने में लगता है। और password के लिए भी वही।
इस तरह, अपने application code में secrets.compare_digest() का उपयोग करके, यह security attacks की इस पूरी range के विरुद्ध सुरक्षित रहेगा।
Error लौटाएँ¶
यह detect करने के बाद कि credentials incorrect हैं, status code 401 (वही जो तब लौटाया जाता है जब कोई credentials provide नहीं किए जाते) के साथ एक HTTPException लौटाएँ और browser को login prompt फिर से दिखाने के लिए WWW-Authenticate header जोड़ें:
import secrets
from typing import Annotated
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import HTTPBasic, HTTPBasicCredentials
app = FastAPI()
security = HTTPBasic()
def get_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
)
if not (is_correct_username and is_correct_password):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Basic"},
)
return credentials.username
@app.get("/users/me")
def read_current_user(username: Annotated[str, Depends(get_current_username)]):
return {"username": username}
🤓 Other versions and variants
Tip
Prefer to use the Annotated version if possible.
import secrets
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import HTTPBasic, HTTPBasicCredentials
app = FastAPI()
security = HTTPBasic()
def get_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
)
if not (is_correct_username and is_correct_password):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Basic"},
)
return credentials.username
@app.get("/users/me")
def read_current_user(username: str = Depends(get_current_username)):
return {"username": username}