Closed unaor closed 8 months ago
I am not quite sure, I understand the issue. You want to allow access to exactly one user? In that case, couldn't you also blacklist based on the username? I.e.:
@manager.user_loader(db=get_db())
def query_user(username: str, token:str, db: SessionLocal):
if username != "myusername":
return None
if isinstance(db, types.GeneratorType):
db = next(get_db())
user: UserModel = db.query(UserModel).filter(UserModel.username==username).first()
return user
I want to allow access to many users of course, but I would like to prevent the same user to login from his phone for example, and from his computer on the same time. for example
token_a =login("some_random_user", "secret_password")
now token_a lives on the device of the some_random_user
however if the same user would go to another device and do
token_b =login("some_random_user", "secret_password")
than i would like to blacklist token_a
and thus basically force log him out from the first device, but allow him to use on the second device with token_b
I see. I am afraid that is not currently possible and I would rather not change the call pattern of the user loader in order to keep backwards compatibility. You could in theory write your own dependency / subclass the login manager to implement this behavior there:
def BlacklistManager(request: Request):
token = manager._get_token(request) # Careful might raise errors if no token is present
if token in blacklist:
# Raise not authenticated
else:
# Return user
return manager(request)
I agree however that this depends on the "private" _get_token
function, which should probably be public anyway.
I probably should change the API in that way.
See also #87 and #82.
thanks that is quite good workaround.
i'm using it like this wdyt
async def blacklistManager(request: Request): <- need it async for the token to resolve
token = await manager._get_token(request)
if token in blacklist:
raise InvalidCredentialsException
return manager(request)
and example usage
@router.get("/", response_model=list[UserSchema])
async def read_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db), requesting_user: UserModel=Depends(blacklistManager)):
requesting_user = await requesting_user <- only way to make it actually authenticate
users = db.query(UserModel).offset(skip).limit(limit).all()
return users
I want to allow user to login and use the application from one device only. I noticed that the current implementation of the
user_loader
only receives one param the decoded username, making it impossible to access the actual token and compare iti'm suggesting the following change to give access to the token
line 229:
user = await self._load_user(user_identifier, token)
line 236:
async def _load_user(self, identifier: typing.Any ,token: str):
now my custom implementation looks like this