Closed agent666 closed 2 years ago
But if I am not logged in yet in the /login and give incorrect login details I am redirected to /login again as planned. But if I'm not logged in and visit /protected I get the above error
@app.post('/login' , response_class=RedirectResponse, status_code=302)
async def login(response: Response, data: OAuth2PasswordRequestForm = Depends()):
username = data.username
password = data.password
user_data = await query_user(username)
if not user_data:
raise NotAuthenticatedException
elif not pwdhasher.verify(password, user_data[1]):
raise NotAuthenticatedException
access_token = manager.create_access_token(
data={'sub': user_data[0]}, expires=timedelta(days=365)
)
@manager.user_loader()
@app.get('/protected', response_class=HTMLResponse)
def protected_route(user=Depends(manager)):
return user
We already had a similar issue about catching FastAPI's HTTPExceptions, this was resolved by changing except self.not_authenticated_exception
to except type(self.not_authenticated_exception)
. However it seems that this breaks catching of standard exception as type(Exception)
returns <class 'type'>
, it also looks like none of my test cases actually checks this.
If I have enough time I will look into this over the weekend.
You can use the following snippet as a "hacky" workaround. What we basically do is subclass HTTPException
instead of the normal exception class from python, as the error handeling for the former should work correctly. Then we modify our exception handler such that it catches all HTTPException
s raised anywhere and checks if the exception is a actually a instance of our subclass.
from fastapi import HTTPException
# This is the default http_exception_handler used out of the box
from fastapi.exception_handlers import http_exception_handler
from starlette.exceptions import HTTPException as StarletteHTTPException
# We have to create a new class so that we can check if the HTTPException in our handler belongs
# to our custom exception
class NotAuthenticatedException(HTTPException):
def __init__(self) -> None:
super().__init__(400) # Error code can basically be any valid http status code as we don't return it
# From the fastapi docs we have to use the StarletteHTTPException here
@app.exception_handler(StarletteHTTPException)
async def auth_exception_handler(request: Request, exc: NotAuthenticatedException):
"""
Redirect the user to the login page if not logged in
"""
if isinstance(exc, NotAuthenticatedException):
return RedirectResponse(url='/login')
else:
# This should be called for any other http exception that does not belong to our "custom" exception class
return await http_exception_handler(request, exc)
# NOTE how we pass a instance of our class to the LoginManager
manager = LoginManager(..., custom_exception=NotAuthenticatedException())
Should be fixed in the newest version.
When I use the example code from https://fastapi-login.readthedocs.io/advanced_usage/ and there is no, or an invalid token present in the request I get an error:
I use:
What do I do wrong?