Issue
Referencing this link: fastapi-supporting-multiple-authentication-dependencies
I think this is the closest to what I need, but somehow I can’t get either of the dependency to work because fastapi is enforcing both dependencies before it grants access to endpoint.
Snippet for custom depedency:
def basic_logged_user(credentials: Annotated[HTTPBasicCredentials, Depends(security)]):
current_username_bytes = credentials.username.encode("utf8")
correct_username_bytes = settings.SESSION_LOGIN_USER.encode("utf8")
is_correct_username = secrets.compare_digest(
current_username_bytes, correct_username_bytes
)
current_password_bytes = credentials.password.encode("utf8")
correct_password_bytes = settings.SESSION_LOGIN_PASS.encode("utf8")
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="Invalid Credentials",
headers={"WWW-Authenticate": "Basic"},
)
return credentials.username
def jwt_logged_user(token: str = Depends(utils.OAuth2_scheme),
db: Session = Depends(db_session)):
credential_exception = HTTPException(status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Bearer"})
token = utils.verify_token(token, credential_exception)
user = db.query(User).filter(User.username == token.username).first()
return user
# custom auth
def auth_user(jwt_auth: HTTPBearer = Depends(jwt_logged_user),
basic_auth: HTTPBasic = Depends(basic_logged_user)):
if not (jwt_auth or basic_auth):
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED,
detail='Invalid Credentials')
#endpoint
@router.get("/")
async def get_users(db: Session = Depends(db_session), logged_user: str = Depends(auth_user)):
query_users = db.query(User).all()
return query_users
I expect it to grant me access to endpoint when I provide correct credential for JWT auth or Basic Auth, but it still forces me to put in credential for both. How can I achieve this effect of providing any one of the 2 auth but not both.
Solution
The idea is to make all of this security dependencies not to raise exceptions on user authentication error at the dependency resolving stage.
For HTTPBasic
pass auto_error=False
:
security = HTTPBasic(auto_error=False)
And then in basic_logged_user
you should check that
def basic_logged_user(credentials: Annotated[Optional[HTTPBasicCredentials], Depends(security)]):
if credentials is None:
return None
...
# Do not raise exception, but return None instead
You need to find the way how to do the same with your second authentication scheme (utils.OAuth2_scheme
) - not to raise HTTP_401_UNAUTHORIZED
, but return None
instead.
Then your auth_user
will work as you expect. It will raise HTTP_401_UNAUTHORIZED
only if both schemes return None
.
Answered By - Yurii Motov
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.