Using Oauth2 with scope, error - "Depends" has no attribute "query" - FastAPI - python

authentication.py
from datetime import datetime, timedelta
from fastapi import Depends , HTTPException, status, Security
from fastapi.security import OAuth2PasswordBearer, SecurityScopes
from jose import JWTError, jwt
from auth.schemas import TokenData, UserBase
from sqlalchemy.orm import Session
from db.database import get_db
from pydantic import ValidationError
from db.models import UserModel
SECRET_KEY = '7f0ef2549adac85716db6ca433a44c79021e829c8c4dd8e7d9363eb9fc800e73'
ALGORITHM = 'HS256'
ACCESS_TOKEN_EXPIRE_MINUTES = 30
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="login",
scopes={"admin":"create content", "user":"interact with content"}
)
def get_user(email: str,db:Session=Depends(get_db)):
user = db.query(UserModel).filter(UserModel.email == email).first()
if not user:
raise HTTPException(status=status.HTTP_404_NOT_FOUND,
details=f"User with email: {email} not found")
return user
async def get_current_user(
security_scopes: SecurityScopes, token: str = Depends(oauth2_scheme)
):
if security_scopes.scopes:
authenticate_value = f'Bearer scope="{security_scopes.scope_str}"'
else:
authenticate_value = f"Bearer"
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": authenticate_value},
)
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
if username is None:
raise credentials_exception
token_scopes = payload.get("scopes", [])
token_data = TokenData(scopes=token_scopes, username=username)
except (JWTError, ValidationError):
raise credentials_exception
user = get_user(email=token_data.email)
if user is None:
raise credentials_exception
for scope in security_scopes.scopes:
if scope not in token_data.scopes:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="not enough permission",
headers={"WWW-Authenticate": authenticate_value},
)
return user
def get_current_active_user(
current_user:UserBase = Security(get_current_user, scopes=["admin"])):
if not current_user:
raise HTTPException(status_code=400, detail="Inactive user")
return current_user
def create_access_token(data:dict):
to_encode = data.copy()
expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode,SECRET_KEY,algorithm=ALGORITHM)
return encoded_jwt
def verify_token(token:str,credentials_exception):
try:
payload = jwt.decode(token,SECRET_KEY,algorithms=ALGORITHM)
email:str = payload.get("sub")
if email is None:
raise credentials_exception
token_data = TokenData(email=email)
return token_data
except JWTError:
raise credentials_exception
login
from fastapi import APIRouter, Depends,HTTPException,status
from fastapi.security import OAuth2PasswordRequestForm, OAuth2PasswordBearer
from sqlalchemy.orm import Session
from db.models import UserModel
from db.database import get_db
from . import hashing
from auth.oauth import create_access_token
from .hashing import get_password_hash
from .schemas import UserBase
router = APIRouter(tags=['authentication'])
#router.post('/login')
async def login(request:OAuth2PasswordRequestForm=Depends(),db:Session=Depends(get_db)):
user = db.query(UserModel).filter(UserModel.email == request.username).first()
if not user:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,detail="Invalid Credentials")
if not hashing.verify_password(request.password,user.password):
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST,detail="Invalid Password")
access_token = create_access_token(data={"sub":user.username,"scopes":request.scopes})
return {"access_token":access_token,"token_type":"bearer"}
#router.post('/register')
async def register(request:UserBase,db:Session=Depends(get_db)):
new_user = UserModel(
email = request.email,
username = request.username,
password = get_password_hash(request.password),
)
db.add(new_user)
db.commit()
db.refresh(new_user)
return new_user
endpoints
from fastapi import APIRouter, Depends, Security
from auth.oauth import get_current_active_user
from routers.schemas import BikeBase
from sqlalchemy.orm import Session
from db.database import get_db
from db.models import BikeModel
from .crud import add_bike
from auth.schemas import UserBase
router = APIRouter(
prefix='/bike',
tags = ['bike']
)
#router.post('/add')
def add_bike(request:BikeBase,user:UserBase=Depends(get_current_active_user),db:Session=Depends(get_db)):
bike = db.query(BikeModel).filter(BikeModel.model==request.model).first()
if bike is None:
return add_bike(request,user)
if request.model in bike:
raise Exception("Bike Model Already present")
return add_bike(request,user)
#router.get('/check')
def check(user:UserBase=Security(get_current_active_user, scopes=["admin"])):
return {"data":"scope working"}
def add_bike(request:BikeBase,user=Security(get_current_active_user, scopes=["admin"]),db:Session=Depends(get_db)):
new_bike = BikeBase(
brand = request.brand.lower(),
model = request.model.lower(),
price = request.price,
mileage = request.mileage,
max_power = request.max_power,
rating = request.rating
)
db.add(new_bike)
db.commit()
db.refresh(new_bike)
return new_bike
On the #router.post('/add') getting the error:
File "/home/raj/code/bike-forum-fastapi/./auth/oauth.py", line 24, in get_user
user = db.query(UserModel).filter(UserModel.email == email).first()
AttributeError: 'Depends' object has no attribute 'query'
When i change some endpoints to async the error changes something with coroutine, i cant remember how to produce it
#router.check('/check') endpoint works fine with scope and permission, but produces error at #router.post('/add')
i new to fastapi, the auth code is directly copied from fastapi-docs, but theres a hardcoded fake database for get_user in docs, i cant figure how to do it with a real database

Related

422 Unprocessable Entity

Here is my code:
from fastapi import (FastAPI, BackgroundTasks, UploadFile,
File, Form, Depends, HTTPException, status, Request)
from tortoise.contrib.fastapi import register_tortoise
from models import (User, Business, Product, user_pydantic, user_pydanticIn,
product_pydantic,product_pydanticIn, business_pydantic,
business_pydanticIn, user_pydanticOut)
# signals
from tortoise.signals import post_save
from typing import List, Optional, Type
from tortoise import BaseDBAsyncClient
from starlette.responses import JSONResponse
from starlette.requests import Request
#authentication and authorization
import jwt
from dotenv import dotenv_values
from fastapi.security import (
OAuth2PasswordBearer,
OAuth2PasswordRequestForm
)
# self packages
from emails import *
from authentication import *
from dotenv import dotenv_values
import math
# user image uploads
# pip install python-multipart
from fastapi import File, UploadFile
import secrets
# static files
from fastapi.staticfiles import StaticFiles
# pillow
from PIL import Image
# templates
from fastapi.templating import Jinja2Templates
# HTMLResponse
from fastapi.responses import HTMLResponse
config_credentials = dict(dotenv_values(".env"))
app = FastAPI()
# static files
# pip install aiofiles
app.mount("/static", StaticFiles(directory="static"), name="static")
# authorization configs
oath2_scheme = OAuth2PasswordBearer(tokenUrl = 'token')
# password helper functions
#app.post('/token')
async def generate_token(request_form: OAuth2PasswordRequestForm = Depends()):
token = await token_generator(request_form.username, request_form.password)
return {'access_token' : token, 'token_type' : 'bearer'}
# process signals here
#post_save(User)
async def create_business(
sender: "Type[User]",
instance: User,
created: bool,
using_db: "Optional[BaseDBAsyncClient]",
update_fields: List[str]) -> None:
if created:
business_obj = await Business.create(
business_name = instance.username, owner = instance)
await business_pydantic.from_tortoise_orm(business_obj)
# send email functionality
await send_email([instance.email], instance)
#app.post('/registration')
async def user_registration(user: user_pydanticIn):
user_info = user.dict(exclude_unset = True)
user_info['password'] = get_password_hash(user_info['password'])
user_obj = await User.create(**user_info)
new_user = await user_pydantic.from_tortoise_orm(user_obj)
return {"status" : "ok",
"data" :
f"Hello {new_user.username} thanks for choosing our services. Please check your email inbox and click on the link to confirm your registration."}
# template for email verification
templates = Jinja2Templates(directory="templates")
#app.get('/verification', response_class=HTMLResponse)
# make sure to import request from fastapi and HTMLResponse
async def email_verification(request: Request, token: str):
user = await verify_token(token)
if user and not user.is_verified:
user.is_verified = True
await user.save()
return templates.TemplateResponse("verification.html",
{"request": request, "username": user.username}
)
raise HTTPException(
status_code = status.HTTP_401_UNAUTHORIZED,
detail = "Invalid or expired token",
headers={"WWW-Authenticate": "Bearer"},
)
async def get_current_user(token: str = Depends(oath2_scheme)):
try:
payload = jwt.decode(token, config_credentials['SECRET'], algorithms = ['HS256'])
user = await User.get(id = payload.get("id"))
except:
raise HTTPException(
status_code = status.HTTP_401_UNAUTHORIZED,
detail = "Invalid username or password",
headers={"WWW-Authenticate": "Bearer"},
)
return await user
#app.post('/user/me')
async def user_login(user: user_pydantic = Depends(get_current_user)):
business = await Business.get(owner = user)
logo = business.logo
logo = "localhost:8000/static/images/"+logo
return {"status" : "ok",
"data" :
{
"username" : user.username,
"email" : user.email,
"verified" : user.is_verified,
"join_date" : user.join_date.strftime("%b %d %Y"),
"logo" : logo
}
}
#app.post("/products")
async def add_new_product(product: product_pydanticIn,
user: user_pydantic = Depends(get_current_user)):
product = product.dict(exclude_unset = True)
# to avoid division by zero error
if product['original_price'] > 0:
product["percentage_discount"] = ((product["original_price"] - product['new_price'] )/ product['original_price']) * 100
product_obj = await Product.create(**product, business = user)
product_obj = await product_pydantic.from_tortoise_orm(product_obj)
return {"status" : "ok", "data" : product_obj}
#app.get("/products")
async def get_products():
response = await product_pydantic.from_tortoise_orm(Product.all())
return {"status" : "ok", "data" : response}
#app.get("/products/{id}")
async def specific_product(id: int):
product = await Product.get(id = id)
business = await product.business
owner = await business.owner
response = await product_pydantic.from_queryset_single(Product.get(id = id))
print(type(response))
return {"status" : "ok",
"data" :
{
"product_details" : response,
"business_details" : {
"name" : business.business_name,
"city" : business.city,
"region" : business.region,
"description" : business.business_description,
"logo" : business.logo,
"owner_id" : owner.id,
"email" : owner.email,
"join_date" : owner.join_date.strftime("%b %d %Y")
}
}
}
#app.delete("/products/{id}")
async def delete_product(id: int, user: user_pydantic = Depends(get_current_user)):
product = await Product.get(id = id)
business = await product.business
owner = await business.owner
if user == owner:
product.delete()
else:
raise HTTPException(
status_code = status.HTTP_401_UNAUTHORIZED,
detail = "Not authenticated to perform this action",
headers={"WWW-Authenticate": "Bearer"},
)
return {"status" : "ok"}
# image upload
#app.post("/uploadfile/profile")
async def create_upload_file(file: UploadFile = File(...),
user: user_pydantic = Depends(get_current_user)):
FILEPATH = "./static/images/"
filename = file.filename
extension = filename.split(".")[1]
if extension not in ["jpg", "png"]:
return {"status" : "error", "detail" : "file extension not allowed"}
token_name = secrets.token_hex(10)+"."+extension
generated_name = FILEPATH + token_name
file_content = await file.read()
with open(generated_name, "wb") as file:
file.write(file_content)
# pillow
img = Image.open(generated_name)
img = img.resize(size = (200,200))
img.save(generated_name)
file.close()
business = await Business.get(owner = user)
owner = await business.owner
# check if the user making the request is authenticated
print(user.id)
print(owner.id)
if owner == user:
business.logo = token_name
await business.save()
else:
raise HTTPException(
status_code = status.HTTP_401_UNAUTHORIZED,
detail = "Not authenticated to perform this action",
headers={"WWW-Authenticate": "Bearer"},
)
file_url = "localhost:8000" + generated_name[1:]
return {"status": "ok", "filename": file_url}
#app.post("/uploadfile/product/{id}")
# check for product owner before making the changes.
async def create_upload_file(id: int, file: UploadFile = File(...),
user: user_pydantic = Depends(get_current_user)):
FILEPATH = "./static/images/"
filename = file.filename
extension = filename.split(".")[1]
if extension not in ["jpg", "png"]:
return {"status" : "error", "detail" : "file extension not allowed"}
token_name = secrets.token_hex(10)+"."+extension
generated_name = FILEPATH + token_name
file_content = await file.read()
with open(generated_name, "wb") as file:
file.write(file_content)
# pillow
img = Image.open(generated_name)
img = img.resize(size = (200,200))
img.save(generated_name)
file.close()
#get product details
product = await Product.get(id = id)
business = await product.business
owner = await business.owner
# check if the user making the request is authenticated
if owner == user:
product.product_image = token_name
await product.save()
else:
raise HTTPException(
status_code = status.HTTP_401_UNAUTHORIZED,
detail = "Not authenticated to perform this action",
headers={"WWW-Authenticate": "Bearer"},
)
file_url = "localhost:8000" + generated_name[1:]
return {"status": "ok", "filename": file_url}
register_tortoise(
app,
db_url='sqlite://database.sqlite3',
modules={'models': ['models']},
generate_schemas = True,
add_exception_handlers = True
)
When im opening up http://127.0.0.1:8000/docs and try the "/registration" request I get the error: Code: 422 Details: Error: Unprocessable Entity`
Response body:
{
"detail": [
{
"loc": [],
"msg": "UNIQUE constraint failed: user.username",
"type": "IntegrityError"
}
]
}
Response headers:
content-length: 95
content-type: application/json
date: Sun,04 Dec 2022 23:22:02 GMT
server: uvicorn
And in the console I get:
127.0.0.1:54566 - "POST /registration HTTP/1.1" 422 Unprocessable Entity
After some debugging I think that the line 86
user_obj = await User.create(**user_info)
Is causing problems, but I can't seem to be able to fix the issue. Feel free to ask for any additional information
UPD: I was followng Princekrampah's guide on youtube, the git link to the repo is: https://github.com/Princekrampah/learningFastAPI/tree/master/shoppingAPI

make fastapi middleware returning custom http status instead of AuthenticationError status 400

In the following example when you pass a username in the basic auth field it raise a basic 400 error, but i want to return 401 since it's related to the authentication system.
I did tried Fastapi exceptions classes but they do not raise (i presume since we are in a starlette middleware). Il also tried JSONResponse from starlette but it doesn't work either.
AuthenticationError work and raise a 400 but it's juste an empty class that inherit from Exception so no status code can be given.
Fully working example:
import base64
import binascii
import uvicorn
from fastapi import Depends, FastAPI, HTTPException, Request
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer, HTTPBasic
from starlette.authentication import AuthenticationBackend, AuthCredentials, AuthenticationError, BaseUser
from starlette.middleware import Middleware
from starlette.middleware.authentication import AuthenticationMiddleware
from starlette.responses import JSONResponse
class SimpleUserTest(BaseUser):
"""
user object returned to route
"""
def __init__(self, username: str, test1: str, test2: str) -> None:
self.username = username
self.test1 = test1
self.test2 = test2
#property
def is_authenticated(self) -> bool:
return True
async def jwt_auth(auth: HTTPAuthorizationCredentials = Depends(HTTPBearer(auto_error=False))):
if auth:
return True
async def key_auth(apikey_header=Depends(HTTPBasic(auto_error=False))):
if apikey_header:
return True
class BasicAuthBackend(AuthenticationBackend):
async def authenticate(self, conn):
if "Authorization" not in conn.headers:
return
auth = conn.headers["Authorization"]
try:
scheme, credentials = auth.split()
if scheme.lower() == 'bearer':
# check bearer content and decode it
user: dict = {"username": "bearer", "test1": "test1", "test2": "test2"}
elif scheme.lower() == 'basic':
decoded = base64.b64decode(credentials).decode("ascii")
username, _, password = decoded.partition(":")
if username:
# check redis here instead of return dict
print("try error raise")
raise AuthenticationError('Invalid basic auth credentials') # <= raise 400, we need 401
# user: dict = {"username": "basic auth", "test1": "test1", "test2": "test2"}
else:
print("error should raise")
return JSONResponse(status_code=401, content={'reason': str("You need to provide a username")})
else:
return JSONResponse(status_code=401, content={'reason': str("Authentication type is not supported")})
except (ValueError, UnicodeDecodeError, binascii.Error) as exc:
raise AuthenticationError('Invalid basic auth credentials')
return AuthCredentials(["authenticated"]), SimpleUserTest(**user)
async def jwt_or_key_auth(jwt_result=Depends(jwt_auth), key_result=Depends(key_auth)):
if not (key_result or jwt_result):
raise HTTPException(status_code=401, detail="Not authenticated")
app = FastAPI(
dependencies=[Depends(jwt_or_key_auth)],
middleware=[Middleware(AuthenticationMiddleware, backend=BasicAuthBackend())]
)
#app.get("/")
async def read_items(request: Request) -> str:
return request.user.__dict__
if __name__ == "__main__":
uvicorn.run("main:app", host="127.0.0.1", port=5000, log_level="info")
if we set username in basic auth:
INFO: 127.0.0.1:22930 - "GET / HTTP/1.1" 400 Bad Request
so i ended up using on_error as suggested by #MatsLindh
old app:
app = FastAPI(
dependencies=[Depends(jwt_or_key_auth)],
middleware=[
Middleware(
AuthenticationMiddleware,
backend=BasicAuthBackend(),
)
],
)
new version:
app = FastAPI(
dependencies=[Depends(jwt_or_key_auth)],
middleware=[
Middleware(
AuthenticationMiddleware,
backend=BasicAuthBackend(),
on_error=lambda conn, exc: JSONResponse({"detail": str(exc)}, status_code=401),
)
],
)
I choose to use JSONResponse and return a "detail" key/value to emulate a classic 401 fastapi httperror

How authentic JWS with test client Fastapi

I'm trying to test a endpoint that depends a jwt authentication but don't know how make this, especially send the authentication or skip, please an advice will be very useful.
My code give me that error :
AssertionError: {"detail":"Not authenticated"}
router:
#router.post(
path="/api/users",
response_model=UsersRespose,
status_code=status.HTTP_201_CREATED,
summary="Create a new Users Survey",
tags = ["Users"]
)
async def create_user_survey(
user:Users,
db: Session = Depends(get_db),
admin: Admins= Depends(get_curret_admin)
):
db_user = await get_users_by_email(db,email=user.users_email)
if db_user:
raise HTTPException(status_code=400, detail="El correo electronico ya existe")
return await create_users_survey(db=db, user=user)
dependency:
async def create_token(admin:Admin):
admin_obj = Admins.from_orm(admin)
token = encode(admin_obj.dict(), JWT_SECRET)
return dict(access_token=token, token_type="bearer")
async def get_curret_admin(db: Session=Depends(get_db), token: str = Depends(oauth2schema)):
try:
payload=decode(token, JWT_SECRET, algorithms=["HS256"])
admin= db.query(Admin).get(payload["id"])
except:
raise HTTPException(
status_code=401,
detail="Correo o password invalido"
)
return Admins.from_orm(admin)
and test
SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(
SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
)
TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base.metadata.create_all(bind=engine)
def override_get_db():
try:
db = TestingSessionLocal()
yield db
finally:
db.close()
app.dependency_overrides[get_db] = override_get_db
client = TestClient(app)
def test_create_user():
mail=random_email_user()
name =random_name_user()
password = random_pasword_user()
id=random_int_user()
response=client.post("/api/users", json={"users_email":mail ,"id":id, "users_name": name},)
assert response.status_code == 201, response.text
data = response.json()
assert data["users_email"] == mail
Thanks to #MatsLindh the solution was quite simple
def override_get_currrent_admin():
return {"email":"dummy#dummy.com", "name_admin":"dummy", "id":"5"}
app.dependency_overrides[get_curret_admin]= override_get_currrent_admin

how to logout from jwt security scheme in fastapi

I am trying to write a logout function in fastapi. For logging out from server side, I am setting the token expiry time to 0 and sending it to client, expecting that this would invalidate the token right at that movement. However, it is not working as expect and even after logout I am able to access the protected APIs. What is wrong here? It this a good approach to logout in jwt scheme? Please help.
from datetime import datetime, timedelta
from typing import Optional
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jose import JWTError, jwt
from passlib.context import CryptContext
from pydantic import BaseModel
import uvicorn
import pytz
SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_SECONDS = 200 # expire the token, even though user has not logged out. Change the time for your testing.
utc=pytz.UTC
fake_users_db = {
"johndoe": {
"username": "johndoe",
"full_name": "John Doe",
"email": "johndoe#example.com",
"hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW",
"disabled": False,
},
"ravi": {
"username": "ravi",
"full_name": "ravi singh",
"email": "ravi.singh#gmail.com",
"hashed_password": "$2b$12$ODf2vUEfanF3P1JykF0CgO7jafMA9RWCuqZxLUAqCcQJ1FYxxFROC",
"disabled": False,
},
"alice": {
"username": "alice",
"full_name": "Alice Wonderson",
"email": "alice#example.com",
"hashed_password": "fakehashedsecret2",
"disabled": True,
},
}
class Token(BaseModel):
access_token: str
token_type: str
class TokenData(BaseModel):
username: Optional[str] = None
expires: datetime
class User(BaseModel):
username: str
email: Optional[str] = None
full_name: Optional[str] = None
disabled: Optional[bool] = None
class UserInDB(User):
hashed_password: str
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
app = FastAPI()
def verify_password(plain_password, hashed_password):
return pwd_context.verify(plain_password, hashed_password)
def get_password_hash(password):
return pwd_context.hash(password)
def get_user(db, username: str):
if username in db:
user_dict = db[username]
return UserInDB(**user_dict)
def authenticate_user(fake_db, username: str, password: str):
user = get_user(fake_db, username)
if not user:
return False
if not verify_password(password, user.hashed_password):
return False
return user
def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
to_encode = data.copy()
if expires_delta:
expire = datetime.utcnow() + expires_delta
else:
expire = datetime.utcnow() + timedelta(minutes=15)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
# get the current user from auth token
async def get_current_user(token: str = Depends(oauth2_scheme)):
# define credential exception
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
try:
# decode token and extract username and expires data
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
exps:int = payload.get("exp")
# validate username
if username is None:
raise credentials_exception
token_data = TokenData(username=username, expires=exps) # exps of int is converted to datetime type
except JWTError:
raise credentials_exception
user = get_user(fake_users_db, username=token_data.username)
if user is None:
raise credentials_exception
# check token expiration
if exps is None:
raise credentials_exception
if utc.localize(datetime.utcnow()) > token_data.expires:
print("Token is expired.\n")
raise credentials_exception
return user
async def get_current_active_user(current_user: User = Depends(get_current_user)):
if current_user.disabled:
raise HTTPException(status_code=400, detail="Inactive user")
return current_user
#app.post("/token", response_model=Token)
async def login(form_data: OAuth2PasswordRequestForm = Depends()): # login function to get access token
user = authenticate_user(fake_users_db, form_data.username, form_data.password)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Bearer"},
)
access_token_expires = timedelta(seconds=ACCESS_TOKEN_EXPIRE_SECONDS)
access_token = create_access_token(
data={"sub": user.username}, expires_delta=access_token_expires
)
return {"access_token": access_token, "token_type": "bearer"}
#app.post("/logout", response_model=Token)
async def logout(current_user: User = Depends(get_current_active_user)): # logout function to delete access token
token_data = TokenData(username=current_user.username, expires=0)
return token_data
#return "User logout sucessful."
#app.get("/users/me/", response_model=User)
async def read_users_me(current_user: User = Depends(get_current_active_user)):
return current_user
#app.get("/users/me/items/")
async def read_own_items(current_user: User = Depends(get_current_active_user)):
return [{"item_id": "Foo", "owner": current_user.username}]
#app.get("/protected_hi")
async def protected_hi(current_user: User = Depends(get_current_active_user)):
return "Hi! How are you? You are in a protected Zone."
#app.get("/unprotected_hi")
async def unprotected_hi():
return "Hi! How are you? You are in an un-protected Zone."
if __name__ == "__main__":
import uvicorn
uvicorn.run('jwt_fourth:app', host="0.0.0.0", port=5000, reload=True)

Fastapi OAuth2PasswordRequestForm - add a custom field 'rentalpoint' into validation form

Is it possible to add a custom field into the OAuth2PasswordRequestForm? I need the content of the field to be returned in the token as "rentalpoint". Now in the return "rentalpoint" holds a fixed string "rentalpoint": "cologne" but i want to replace it with something like this: "rentalpoint": request.rentalpoint. How can i do that?
#router.post('/')
def login(request: OAuth2PasswordRequestForm = Depends(), db: Session = Depends(database.get_db)):
user = db.query(models.User).filter(models.User.email == request.username).first()
if not user:
raise HTTPException(status_code = status.HTTP_404_NOT_FOUND, detail='Invalid credentials')
if not Hash.verify(user.password, request.password):
raise HTTPException(status_code = status.HTTP_404_NOT_FOUND, detail='Incorrect password')
access_token = JWTtoken.create_access_token(data={"sub": user.email})
return {"access_token": access_token, "token_type": "bearer", "rentalpoint": "cologne", "user_id": request.username}

Categories