FastAPI OAuth2 प्रमाणीकरण में महारत हासिल करें! यह गाइड पासवर्ड फ्लो, इम्प्लिसिट फ्लो, ऑथराइजेशन कोड फ्लो, टोकन रिफ्रेश और मजबूत API बनाने के लिए सुरक्षा सर्वोत्तम प्रथाओं को कवर करती है।
FastAPI OAuth2 इम्प्लीमेंटेशन: एक व्यापक प्रमाणीकरण प्रवाह गाइड
आज के डिजिटल परिदृश्य में, अपने API को सुरक्षित करना अत्यंत महत्वपूर्ण है। OAuth2 (ओपन ऑथराइजेशन) प्रत्यायोजित प्राधिकरण के लिए उद्योग मानक बन गया है, जिससे उपयोगकर्ता अपनी क्रेडेंशियल साझा किए बिना अपने संसाधनों तक सीमित पहुंच प्रदान कर सकते हैं। FastAPI, एक आधुनिक, उच्च-प्रदर्शन वाला पाइथन वेब फ्रेमवर्क, OAuth2 प्रमाणीकरण को लागू करना आसान बनाता है। यह व्यापक गाइड आपको विभिन्न OAuth2 फ्लो से अवगत कराएगी और दिखाएगी कि उन्हें अपने FastAPI एप्लिकेशन में कैसे एकीकृत करें, यह सुनिश्चित करते हुए कि आपका API सुरक्षित और सुलभ बना रहे।
OAuth2 अवधारणाओं को समझना
कोड में उतरने से पहले, आइए हम मुख्य OAuth2 अवधारणाओं की स्पष्ट समझ स्थापित करें:
- संसाधन स्वामी (Resource Owner): वह उपयोगकर्ता जो डेटा का मालिक है और पहुंच प्रदान करता है।
- क्लाइंट (Client): वह एप्लिकेशन जो संसाधन स्वामी के डेटा तक पहुंच का अनुरोध कर रहा है। यह एक वेब एप्लिकेशन, मोबाइल ऐप, या कोई अन्य सेवा हो सकती है।
- प्राधिकरण सर्वर (Authorization Server): संसाधन स्वामी को प्रमाणित करता है और क्लाइंट को प्राधिकरण प्रदान करता है।
- संसाधन सर्वर (Resource Server): संरक्षित संसाधनों को होस्ट करता है और पहुंच प्रदान करने से पहले एक्सेस टोकन को सत्यापित करता है।
- एक्सेस टोकन (Access Token): एक क्रेडेंशियल जो संसाधन स्वामी द्वारा क्लाइंट को दिए गए प्राधिकरण का प्रतिनिधित्व करता है।
- रिफ्रेश टोकन (Refresh Token): एक दीर्घकालिक क्रेडेंशियल जिसका उपयोग संसाधन स्वामी को पुनः अधिकृत किए बिना नए एक्सेस टोकन प्राप्त करने के लिए किया जाता है।
- स्कोप्स (Scopes): क्लाइंट द्वारा अनुरोध की जा रही विशिष्ट अनुमतियों को परिभाषित करते हैं।
OAuth2 फ्लो: सही तरीका चुनना
OAuth2 कई प्राधिकरण फ्लो को परिभाषित करता है, जिनमें से प्रत्येक विभिन्न परिदृश्यों के लिए उपयुक्त है। यहां सबसे सामान्य फ्लो और उनका उपयोग कब करना है, इसका विवरण दिया गया है:
1. पासवर्ड (संसाधन स्वामी पासवर्ड क्रेडेंशियल) फ्लो
विवरण: क्लाइंट सीधे प्राधिकरण सर्वर से एक्सेस टोकन प्राप्त करता है, संसाधन स्वामी का उपयोगकर्ता नाम और पासवर्ड प्रदान करके। उपयोग का मामला: अत्यधिक विश्वसनीय एप्लिकेशन, जैसे फर्स्ट-पार्टी मोबाइल ऐप। इसका उपयोग तभी किया जाना चाहिए जब अन्य फ्लो संभव न हों। फायदे: लागू करने में सरल। नुकसान: क्लाइंट को संसाधन स्वामी के क्रेडेंशियल को संभालना पड़ता है, जिससे क्लाइंट के साथ समझौता होने पर एक्सपोजर का जोखिम बढ़ जाता है। अन्य फ्लो की तुलना में कम सुरक्षित। उदाहरण: एक कंपनी का अपना मोबाइल ऐप जो उनके आंतरिक API तक पहुंच रहा है।
FastAPI में इम्प्लीमेंटेशन:
सबसे पहले, आवश्यक पैकेज इंस्टॉल करें:
pip install fastapi uvicorn python-multipart passlib[bcrypt] python-jose[cryptography]
अब, आइए एक मूल उदाहरण बनाएं:
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import OAuth2PasswordRequestForm
from jose import JWTError, jwt
from passlib.context import CryptContext
from datetime import datetime, timedelta
app = FastAPI()
# Replace with a strong, randomly generated secret key
SECRET_KEY = "YOUR_SECRET_KEY"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
# Password hashing configuration
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
# Dummy user database (replace with a real database in production)
users = {
"johndoe": {
"username": "johndoe",
"hashed_password": pwd_context.hash("password123"),
"scopes": ["read", "write"]
}
}
# Function to verify password
def verify_password(plain_password, hashed_password):
return pwd_context.verify(plain_password, hashed_password)
# Function to create access token
def create_access_token(data: dict, expires_delta: timedelta):
to_encode = data.copy()
expire = datetime.utcnow() + expires_delta
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
# OAuth2 endpoint for token generation
@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
user = users.get(form_data.username)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Bearer"},
)
if not verify_password(form_data.password, user["hashed_password"]):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Bearer"},
)
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
access_token = create_access_token(
data={"sub": user["username"], "scopes": user["scopes"]},
expires_delta=access_token_expires,
)
return {"access_token": access_token, "token_type": "bearer"}
# Dependency to authenticate requests
async def get_current_user(token: str):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
if username is None:
raise credentials_exception
except JWTError:
raise credentials_exception
user = users.get(username)
if user is None:
raise credentials_exception
return user
async def get_current_active_user(current_user = Depends(get_current_user)):
return current_user
# Example protected endpoint
@app.get("/users/me")
async def read_users_me(current_user = Depends(get_current_active_user)):
return {"username": current_user["username"], "scopes": current_user["scopes"]}
स्पष्टीकरण:
- निर्भरताएँ (Dependencies): हम उपयोगकर्ता नाम और पासवर्ड को संभालने के लिए `fastapi.security.OAuth2PasswordRequestForm` का उपयोग करते हैं।
- पासवर्ड हैशिंग (Password Hashing): पासवर्ड को सुरक्षित रूप से हैश करने और सत्यापित करने के लिए `passlib` का उपयोग किया जाता है। पासवर्ड को कभी भी सादे टेक्स्ट में स्टोर न करें!
- JWT जेनरेशन (JWT Generation): JSON वेब टोकन (JWTs) बनाने और सत्यापित करने के लिए `python-jose` का उपयोग किया जाता है।
- `/token` एंडपॉइंट: यह एंडपॉइंट लॉगिन प्रक्रिया को संभालता है। यह उपयोगकर्ता नाम और पासवर्ड को मान्य करता है, और यदि वैध है, तो एक एक्सेस टोकन उत्पन्न करता है।
- `get_current_user` निर्भरता: यह फ़ंक्शन एक्सेस टोकन को सत्यापित करता है और उपयोगकर्ता को पुनः प्राप्त करता है।
- `/users/me` एंडपॉइंट: यह एक संरक्षित एंडपॉइंट है जिसे एक्सेस करने के लिए एक वैध एक्सेस टोकन की आवश्यकता होती है।
2. इम्प्लिसिट फ्लो
विवरण: संसाधन स्वामी के प्रमाणीकरण के बाद क्लाइंट सीधे प्राधिकरण सर्वर से एक्सेस टोकन प्राप्त करता है। एक्सेस टोकन URL फ्रैगमेंट में वापस किया जाता है। उपयोग का मामला: सिंगल-पेज एप्लिकेशन (SPAs) और अन्य ब्राउज़र-आधारित एप्लिकेशन जहां क्लाइंट सीक्रेट को स्टोर करना संभव नहीं है। फायदे: ब्राउज़र-आधारित एप्लिकेशन के लिए सरल। नुकसान: अन्य फ्लो की तुलना में कम सुरक्षित क्योंकि एक्सेस टोकन URL में उजागर होता है। कोई रिफ्रेश टोकन जारी नहीं किया जाता है। उदाहरण: एक जावास्क्रिप्ट एप्लिकेशन जो एक सोशल मीडिया API तक पहुंच रहा है।
FastAPI में इम्प्लीमेंटेशन संबंधी विचार:
हालांकि FastAPI इम्प्लिसिट फ्लो के फ्रंटएंड पहलुओं को सीधे नहीं संभालता है (क्योंकि यह मुख्य रूप से एक बैकएंड फ्रेमवर्क है), आप प्रमाणीकरण प्रवाह को प्रबंधित करने के लिए रिएक्ट, व्यू या एंगुलर जैसे फ्रंटएंड फ्रेमवर्क का उपयोग करेंगे। FastAPI मुख्य रूप से संसाधन सर्वर के रूप में कार्य करेगा।
सरलीकृत बैकएंड (FastAPI - संसाधन सर्वर) उदाहरण:
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import OAuth2AuthorizationCodeBearer
from jose import JWTError, jwt
app = FastAPI()
# Replace with a strong, randomly generated secret key
SECRET_KEY = "YOUR_SECRET_KEY"
ALGORITHM = "HS256"
# Dummy user database (replace with a real database in production)
users = {
"johndoe": {
"username": "johndoe",
"scopes": ["read", "write"]
}
}
# OAuth2 scheme - using AuthorizationCodeBearer for token verification
oauth2_scheme = OAuth2AuthorizationCodeBearer(authorizationUrl="/auth", tokenUrl="/token") # These URLs are handled by the Authorization Server (not this FastAPI app).
# Dependency to authenticate requests
async def get_current_user(token: str = Depends(oauth2_scheme)):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
if username is None:
raise credentials_exception
except JWTError:
raise credentials_exception
user = users.get(username)
if user is None:
raise credentials_exception
return user
async def get_current_active_user(current_user = Depends(get_current_user)):
return current_user
# Example protected endpoint
@app.get("/users/me")
async def read_users_me(current_user = Depends(get_current_active_user)):
return {"username": current_user["username"], "scopes": current_user["scopes"]}
FastAPI के साथ इम्प्लिसिट फ्लो के लिए मुख्य बिंदु:
- प्राधिकरण सर्वर की भूमिका: वास्तविक प्राधिकरण और टोकन जारी करना एक अलग प्राधिकरण सर्वर पर होता है। FastAPI टोकन को मान्य करते हुए संसाधन सर्वर के रूप में कार्य करता है।
- फ्रंटएंड हैंडलिंग: फ्रंटएंड एप्लिकेशन (जैसे, रिएक्ट, व्यू) प्राधिकरण सर्वर पर रीडायरेक्ट, उपयोगकर्ता लॉगिन और URL फ्रैगमेंट से एक्सेस टोकन की पुनर्प्राप्ति को संभालता है।
- सुरक्षा संबंधी विचार: URL में एक्सेस टोकन के एक्सपोजर के कारण, HTTPS का उपयोग करना और टोकन के जीवनकाल को छोटा रखना महत्वपूर्ण है। यदि संभव हो तो PKCE के साथ ऑथराइजेशन कोड फ्लो के पक्ष में इम्प्लिसिट फ्लो से बचना चाहिए।
3. प्राधिकरण कोड फ्लो
विवरण: क्लाइंट पहले प्राधिकरण सर्वर से एक प्राधिकरण कोड प्राप्त करता है, जिसे वह फिर एक्सेस टोकन के लिए विनिमय करता है। इस फ्लो में क्लाइंट से प्राधिकरण सर्वर और वापस रीडायरेक्ट शामिल होता है। उपयोग का मामला: वेब एप्लिकेशन और मोबाइल ऐप जहां क्लाइंट सीक्रेट को सुरक्षित रूप से संग्रहीत किया जा सकता है। फायदे: इम्प्लिसिट फ्लो की तुलना में अधिक सुरक्षित क्योंकि एक्सेस टोकन सीधे ब्राउज़र में उजागर नहीं होता है। नुकसान: इम्प्लिसिट फ्लो की तुलना में लागू करना अधिक जटिल। उदाहरण: एक तृतीय-पक्ष एप्लिकेशन जो उपयोगकर्ता के Google ड्राइव डेटा तक पहुंच का अनुरोध कर रहा है।
PKCE (प्रूफ की फॉर कोड एक्सचेंज) के साथ प्राधिकरण कोड फ्लो:
PKCE प्राधिकरण कोड फ्लो का एक विस्तार है जो प्राधिकरण कोड अवरोधन के जोखिम को कम करता है। यह मोबाइल ऐप्स और SPAs के लिए अत्यधिक अनुशंसित है, क्योंकि इसमें क्लाइंट को एक सीक्रेट स्टोर करने की आवश्यकता नहीं होती है।
FastAPI में इम्प्लीमेंटेशन संबंधी विचार: इम्प्लिसिट फ्लो के समान, FastAPI इस फ्लो में मुख्य रूप से संसाधन सर्वर के रूप में कार्य करेगा। एक अलग प्राधिकरण सर्वर प्रमाणीकरण और प्राधिकरण कोड जारी करने के लिए जिम्मेदार है।
सरलीकृत बैकएंड (FastAPI - संसाधन सर्वर) उदाहरण (इम्प्लिसिट फ्लो के समान):
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import OAuth2AuthorizationCodeBearer
from jose import JWTError, jwt
app = FastAPI()
# Replace with a strong, randomly generated secret key
SECRET_KEY = "YOUR_SECRET_KEY"
ALGORITHM = "HS256"
# Dummy user database (replace with a real database in production)
users = {
"johndoe": {
"username": "johndoe",
"scopes": ["read", "write"]
}
}
# OAuth2 scheme - using AuthorizationCodeBearer for token verification
oauth2_scheme = OAuth2AuthorizationCodeBearer(authorizationUrl="/auth", tokenUrl="/token") # These URLs are handled by the Authorization Server.
# Dependency to authenticate requests
async def get_current_user(token: str = Depends(oauth2_scheme)):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
if username is None:
raise credentials_exception
except JWTError:
raise credentials_exception
user = users.get(username)
if user is None:
raise credentials_exception
return user
async def get_current_active_user(current_user = Depends(get_current_user)):
return current_user
# Example protected endpoint
@app.get("/users/me")
async def read_users_me(current_user = Depends(get_current_active_user)):
return {"username": current_user["username"], "scopes": current_user["scopes"]}
FastAPI के साथ PKCE के साथ प्राधिकरण कोड फ्लो के लिए मुख्य बिंदु:
- प्राधिकरण सर्वर की भूमिका: प्राधिकरण सर्वर प्राधिकरण कोड के उत्पादन, PKCE कोड सत्यापनकर्ता के सत्यापन और एक्सेस टोकन जारी करने का प्रबंधन करता है।
- फ्रंटएंड हैंडलिंग: फ्रंटएंड एप्लिकेशन एक कोड सत्यापनकर्ता और कोड चुनौती उत्पन्न करता है, उपयोगकर्ता को प्राधिकरण सर्वर पर रीडायरेक्ट करता है, प्राधिकरण कोड प्राप्त करता है, और इसे एक्सेस टोकन के लिए विनिमय करता है।
- बढ़ी हुई सुरक्षा: PKCE प्राधिकरण कोड अवरोधन हमलों को रोकता है, जिससे यह SPAs और मोबाइल ऐप्स के लिए उपयुक्त हो जाता है।
- अनुशंसित तरीका: PKCE के साथ प्राधिकरण कोड फ्लो आमतौर पर आधुनिक वेब और मोबाइल एप्लिकेशन के लिए सबसे सुरक्षित और अनुशंसित फ्लो है।
4. क्लाइंट क्रेडेंशियल फ्लो
विवरण: क्लाइंट सीधे प्राधिकरण सर्वर के साथ अपने स्वयं के क्रेडेंशियल (क्लाइंट आईडी और क्लाइंट सीक्रेट) का उपयोग करके एक एक्सेस टोकन प्राप्त करने के लिए प्रमाणित होता है। उपयोग का मामला: मशीन-से-मशीन संचार, जैसे बैकएंड सेवाओं का एक-दूसरे तक पहुंचना। फायदे: बैकएंड सेवाओं के लिए सरल। नुकसान: उपयोगकर्ता प्रमाणीकरण के लिए उपयुक्त नहीं। उदाहरण: एक डेटा प्रोसेसिंग सेवा जो एक डेटाबेस सेवा तक पहुंच रही है।
FastAPI में इम्प्लीमेंटेशन:
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import HTTPBasic, HTTPBasicCredentials
from jose import JWTError, jwt
from datetime import datetime, timedelta
app = FastAPI()
# Replace with a strong, randomly generated secret key
SECRET_KEY = "YOUR_SECRET_KEY"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
# Dummy client database (replace with a real database in production)
clients = {
"client_id": {
"client_secret": "client_secret",
"scopes": ["read", "write"]
}
}
# Function to create access token
def create_access_token(data: dict, expires_delta: timedelta):
to_encode = data.copy()
expire = datetime.utcnow() + expires_delta
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
# HTTP Basic Authentication scheme
security = HTTPBasic()
# Endpoint for token generation
@app.post("/token")
async def login(credentials: HTTPBasicCredentials = Depends(security)):
client = clients.get(credentials.username)
if not client:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect client ID or secret",
headers={"WWW-Authenticate": "Basic"},
)
if credentials.password != client["client_secret"]:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect client ID or secret",
headers={"WWW-Authenticate": "Basic"},
)
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
access_token = create_access_token(
data={"sub": credentials.username, "scopes": client["scopes"]},
expires_delta=access_token_expires,
)
return {"access_token": access_token, "token_type": "bearer"}
# Dependency to authenticate requests
async def get_current_client(token: str):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
client_id: str = payload.get("sub")
if client_id is None:
raise credentials_exception
except JWTError:
raise credentials_exception
client = clients.get(client_id)
if client is None:
raise credentials_exception
return client
async def get_current_active_client(current_client = Depends(get_current_client)):
return current_client
# Example protected endpoint
@app.get("/data")
async def read_data(current_client = Depends(get_current_active_client)):
return {"message": "Data accessed by client: " + current_client["client_secret"]}
स्पष्टीकरण:
- HTTP बेसिक प्रमाणीकरण: हम क्लाइंट को प्रमाणित करने के लिए `fastapi.security.HTTPBasic` का उपयोग करते हैं।
- `/token` एंडपॉइंट: यह एंडपॉइंट क्लाइंट प्रमाणीकरण को संभालता है। यह क्लाइंट आईडी और सीक्रेट को मान्य करता है, और यदि वैध है, तो एक एक्सेस टोकन उत्पन्न करता है।
- `get_current_client` निर्भरता: यह फ़ंक्शन एक्सेस टोकन को सत्यापित करता है और क्लाइंट को पुनः प्राप्त करता है।
- `/data` एंडपॉइंट: यह एक संरक्षित एंडपॉइंट है जिसे एक्सेस करने के लिए एक वैध एक्सेस टोकन की आवश्यकता होती है।
टोकन रिफ्रेश
समझौता किए गए टोकन के प्रभाव को कम करने के लिए एक्सेस टोकन का जीवनकाल आमतौर पर छोटा होता है। रिफ्रेश टोकन दीर्घकालिक क्रेडेंशियल होते हैं जिनका उपयोग उपयोगकर्ता को पुनः अधिकृत किए बिना नए एक्सेस टोकन प्राप्त करने के लिए किया जा सकता है।
इम्प्लीमेंटेशन संबंधी विचार:
- रिफ्रेश टोकन को संग्रहीत करना: रिफ्रेश टोकन को सुरक्षित रूप से संग्रहीत किया जाना चाहिए, आदर्श रूप से एक डेटाबेस में एन्क्रिप्टेड।
- रिफ्रेश टोकन एंडपॉइंट: रिफ्रेश टोकन अनुरोधों को संभालने के लिए एक समर्पित एंडपॉइंट (जैसे, `/refresh_token`) बनाएं।
- रिफ्रेश टोकन को रद्द करना: यदि रिफ्रेश टोकन से समझौता किया जाता है या उनकी अब आवश्यकता नहीं है तो उन्हें रद्द करने के लिए एक तंत्र लागू करें।
उदाहरण (पासवर्ड फ्लो उदाहरण का विस्तार):
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import OAuth2PasswordRequestForm
from jose import JWTError, jwt
from passlib.context import CryptContext
from datetime import datetime, timedelta
import secrets # For generating secure random strings
app = FastAPI()
# Replace with a strong, randomly generated secret key
SECRET_KEY = "YOUR_SECRET_KEY"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
REFRESH_TOKEN_EXPIRE_DAYS = 30 # Longer lifetime for refresh tokens
# Password hashing configuration
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
# Dummy user database (replace with a real database in production)
users = {
"johndoe": {
"username": "johndoe",
"hashed_password": pwd_context.hash("password123"),
"scopes": ["read", "write"],
"refresh_token": None # Store refresh token here
}
}
# Function to verify password (same as before)
def verify_password(plain_password, hashed_password):
return pwd_context.verify(plain_password, hashed_password)
# Function to create access token (same as before)
def create_access_token(data: dict, expires_delta: timedelta):
to_encode = data.copy()
expire = datetime.utcnow() + expires_delta
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
# Function to create refresh token
def create_refresh_token():
return secrets.token_urlsafe(32) # Generate a secure random string
# OAuth2 endpoint for token generation
@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
user = users.get(form_data.username)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Bearer"},
)
if not verify_password(form_data.password, user["hashed_password"]):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Bearer"},
)
# Create refresh token and store it (securely in a database in real-world)
refresh_token = create_refresh_token()
user["refresh_token"] = refresh_token # Store it in the user object for now (INSECURE for production)
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
access_token = create_access_token(
data={"sub": user["username"], "scopes": user["scopes"]},
expires_delta=access_token_expires,
)
return {"access_token": access_token, "token_type": "bearer", "refresh_token": refresh_token}
# Endpoint for refreshing the access token
@app.post("/refresh_token")
async def refresh_access_token(refresh_token: str):
# Find user by refresh token (securely query the database)
user = next((user for user in users.values() if user["refresh_token"] == refresh_token), None)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid refresh token",
headers={"WWW-Authenticate": "Bearer"},
)
# Create a new access token
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
access_token = create_access_token(
data={"sub": user["username"], "scopes": user["scopes"]},
expires_delta=access_token_expires,
)
return {"access_token": access_token, "token_type": "bearer"}
# Dependency to authenticate requests (same as before)
async def get_current_user(token: str):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
if username is None:
raise credentials_exception
except JWTError:
raise credentials_exception
user = next((user for user in users.values() if user["username"] == username), None)
if user is None:
raise credentials_exception
return user
async def get_current_active_user(current_user = Depends(get_current_user)):
return current_user
# Example protected endpoint (same as before)
@app.get("/users/me")
async def read_users_me(current_user = Depends(get_current_active_user)):
return {"username": current_user["username"], "scopes": current_user["scopes"]}
महत्वपूर्ण सुरक्षा नोट:
- रिफ्रेश टोकन को संग्रहीत करना: उदाहरण रिफ्रेश टोकन को मेमोरी में (असुरक्षित रूप से) संग्रहीत करता है। एक उत्पादन वातावरण में, रिफ्रेश टोकन को सुरक्षित रूप से एक डेटाबेस में संग्रहीत करें, अधिमानतः एन्क्रिप्टेड।
- रिफ्रेश टोकन रोटेशन: रिफ्रेश टोकन रोटेशन को लागू करने पर विचार करें। रिफ्रेश टोकन का उपयोग करने के बाद, एक नया रिफ्रेश टोकन उत्पन्न करें और पुराने को अमान्य करें। यह समझौता किए गए रिफ्रेश टोकन के प्रभाव को सीमित करता है।
- ऑडिटिंग: संदिग्ध गतिविधि का पता लगाने के लिए रिफ्रेश टोकन उपयोग को लॉग करें।
सुरक्षा सर्वोत्तम प्रथाएँ
OAuth2 को लागू करना केवल पहला कदम है। अपने API और उपयोगकर्ता डेटा की सुरक्षा के लिए सुरक्षा सर्वोत्तम प्रथाओं का पालन करना महत्वपूर्ण है।
- HTTPS का उपयोग करें: क्लाइंट, प्राधिकरण सर्वर और संसाधन सर्वर के बीच संचार को एन्क्रिप्ट करने के लिए हमेशा HTTPS का उपयोग करें।
- इनपुट को मान्य करें: इंजेक्शन हमलों को रोकने के लिए सभी इनपुट डेटा को अच्छी तरह से मान्य करें।
- रेट लिमिटिंग: ब्रूट-फोर्स हमलों को रोकने के लिए रेट लिमिटिंग लागू करें।
- निर्भरताओं को नियमित रूप से अपडेट करें: सुरक्षा कमजोरियों को ठीक करने के लिए अपने FastAPI फ्रेमवर्क और सभी निर्भरताओं को अद्यतित रखें।
- मजबूत सीक्रेट्स का उपयोग करें: अपने क्लाइंट सीक्रेट्स और JWT साइनिंग कीज़ के लिए मजबूत, यादृच्छिक सीक्रेट्स उत्पन्न करें। इन सीक्रेट्स को सुरक्षित रूप से स्टोर करें (उदाहरण के लिए, पर्यावरण चर या एक सीक्रेट्स प्रबंधन प्रणाली का उपयोग करके)।
- मॉनिटर और लॉग करें: संदिग्ध गतिविधि के लिए अपने API की निगरानी करें और सभी प्रमाणीकरण और प्राधिकरण घटनाओं को लॉग करें।
- न्यूनतम विशेषाधिकार लागू करें: क्लाइंट्स को केवल आवश्यक अनुमतियाँ (स्कोप्स) प्रदान करें।
- उचित त्रुटि हैंडलिंग: त्रुटि संदेशों में संवेदनशील जानकारी को उजागर करने से बचें।
- एक अच्छी तरह से जांची गई OAuth2 लाइब्रेरी का उपयोग करने पर विचार करें: खरोंच से OAuth2 को लागू करने के बजाय, Authlib जैसी अच्छी तरह से जांची गई लाइब्रेरी का उपयोग करने पर विचार करें। Authlib OAuth2 का अधिक मजबूत और सुरक्षित इम्प्लीमेंटेशन प्रदान करता है।
बुनियादी बातों से परे: उन्नत विचार
एक बार जब आपके पास एक बुनियादी OAuth2 इम्प्लीमेंटेशन हो जाता है, तो इन उन्नत विषयों पर विचार करें:
- सहमति प्रबंधन: उपयोगकर्ताओं को उन अनुमतियों पर स्पष्ट और दानेदार नियंत्रण प्रदान करें जो वे क्लाइंट को देते हैं।
- प्रत्यायोजित प्राधिकरण: प्रत्यायोजित प्राधिकरण के लिए समर्थन लागू करें, जिससे उपयोगकर्ता क्लाइंट्स को उनकी ओर से कार्य करने के लिए अधिकृत कर सकें।
- मल्टी-फैक्टर प्रमाणीकरण (MFA): सुरक्षा बढ़ाने के लिए MFA को एकीकृत करें।
- फ़ेडरेटेड पहचान: तृतीय-पक्ष पहचान प्रदाताओं (जैसे, Google, Facebook, Twitter) के माध्यम से प्रमाणीकरण का समर्थन करें।
- डायनामिक क्लाइंट पंजीकरण: क्लाइंट्स को आपके प्राधिकरण सर्वर के साथ गतिशील रूप से स्वयं को पंजीकृत करने की अनुमति दें।
निष्कर्ष
FastAPI के साथ OAuth2 प्रमाणीकरण को लागू करना आपके API को सुरक्षित करने और उपयोगकर्ता डेटा की सुरक्षा के लिए एक शक्तिशाली तरीका है। विभिन्न OAuth2 फ्लो को समझकर, सुरक्षा सर्वोत्तम प्रथाओं को लागू करके, और उन्नत विषयों पर विचार करके, आप मजबूत और सुरक्षित API बना सकते हैं जो आपके उपयोगकर्ताओं और अनुप्रयोगों की आवश्यकताओं को पूरा करते हैं। अपने विशिष्ट उपयोग के मामले के लिए उचित फ्लो चुनना, सुरक्षा को प्राथमिकता देना और अपनी प्रमाणीकरण प्रणाली की लगातार निगरानी और सुधार करना याद रखें। जबकि प्रदान किए गए उदाहरण मूलभूत सिद्धांतों को प्रदर्शित करते हैं, उन्हें हमेशा अपनी विशिष्ट आवश्यकताओं के अनुसार अनुकूलित करें और गहन समीक्षा के लिए सुरक्षा विशेषज्ञों से परामर्श करें।