mirror of
https://github.com/fastapi-users/fastapi-users.git
synced 2026-03-13 07:49:55 +08:00
Fix #1043: Add a prefix to the generated key in RedisStrategy
This commit is contained in:
@@ -26,6 +26,7 @@ As you can see, instantiation is quite simple. It accepts the following argument
|
|||||||
|
|
||||||
* `redis` (`redis.asyncio.Redis`): An instance of `redis.asyncio.Redis`. Note that the `decode_responses` flag set to `True` is necessary.
|
* `redis` (`redis.asyncio.Redis`): An instance of `redis.asyncio.Redis`. Note that the `decode_responses` flag set to `True` is necessary.
|
||||||
* `lifetime_seconds` (`Optional[int]`): The lifetime of the token in seconds. Defaults to `None`, which means the token doesn't expire.
|
* `lifetime_seconds` (`Optional[int]`): The lifetime of the token in seconds. Defaults to `None`, which means the token doesn't expire.
|
||||||
|
* `key_prefix` (`str`): The prefix used to set the key in the Redis stored. Defaults to `fastapi_users_token:`.
|
||||||
|
|
||||||
!!! tip "Why it's inside a function?"
|
!!! tip "Why it's inside a function?"
|
||||||
To allow strategies to be instantiated dynamically with other dependencies, they have to be provided as a callable to the authentication backend.
|
To allow strategies to be instantiated dynamically with other dependencies, they have to be provided as a callable to the authentication backend.
|
||||||
|
|||||||
@@ -10,10 +10,15 @@ from fastapi_users.manager import BaseUserManager
|
|||||||
|
|
||||||
class RedisStrategy(Strategy[models.UP, models.ID], Generic[models.UP, models.ID]):
|
class RedisStrategy(Strategy[models.UP, models.ID], Generic[models.UP, models.ID]):
|
||||||
def __init__(
|
def __init__(
|
||||||
self, redis: redis.asyncio.Redis, lifetime_seconds: Optional[int] = None
|
self,
|
||||||
|
redis: redis.asyncio.Redis,
|
||||||
|
lifetime_seconds: Optional[int] = None,
|
||||||
|
*,
|
||||||
|
key_prefix: str = "fastapi_users_token:",
|
||||||
):
|
):
|
||||||
self.redis = redis
|
self.redis = redis
|
||||||
self.lifetime_seconds = lifetime_seconds
|
self.lifetime_seconds = lifetime_seconds
|
||||||
|
self.key_prefix = key_prefix
|
||||||
|
|
||||||
async def read_token(
|
async def read_token(
|
||||||
self, token: Optional[str], user_manager: BaseUserManager[models.UP, models.ID]
|
self, token: Optional[str], user_manager: BaseUserManager[models.UP, models.ID]
|
||||||
@@ -21,7 +26,7 @@ class RedisStrategy(Strategy[models.UP, models.ID], Generic[models.UP, models.ID
|
|||||||
if token is None:
|
if token is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
user_id = await self.redis.get(token)
|
user_id = await self.redis.get(f"{self.key_prefix}{token}")
|
||||||
if user_id is None:
|
if user_id is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -33,8 +38,10 @@ class RedisStrategy(Strategy[models.UP, models.ID], Generic[models.UP, models.ID
|
|||||||
|
|
||||||
async def write_token(self, user: models.UP) -> str:
|
async def write_token(self, user: models.UP) -> str:
|
||||||
token = secrets.token_urlsafe()
|
token = secrets.token_urlsafe()
|
||||||
await self.redis.set(token, str(user.id), ex=self.lifetime_seconds)
|
await self.redis.set(
|
||||||
|
f"{self.key_prefix}{token}", str(user.id), ex=self.lifetime_seconds
|
||||||
|
)
|
||||||
return token
|
return token
|
||||||
|
|
||||||
async def destroy_token(self, token: str, user: models.UP) -> None:
|
async def destroy_token(self, token: str, user: models.UP) -> None:
|
||||||
await self.redis.delete(token)
|
await self.redis.delete(f"{self.key_prefix}{token}")
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ class TestReadToken:
|
|||||||
redis: RedisMock,
|
redis: RedisMock,
|
||||||
user_manager,
|
user_manager,
|
||||||
):
|
):
|
||||||
await redis.set("TOKEN", "bar")
|
await redis.set(f"{redis_strategy.key_prefix}TOKEN", "bar")
|
||||||
authenticated_user = await redis_strategy.read_token("TOKEN", user_manager)
|
authenticated_user = await redis_strategy.read_token("TOKEN", user_manager)
|
||||||
assert authenticated_user is None
|
assert authenticated_user is None
|
||||||
|
|
||||||
@@ -79,7 +79,9 @@ class TestReadToken:
|
|||||||
redis: RedisMock,
|
redis: RedisMock,
|
||||||
user_manager,
|
user_manager,
|
||||||
):
|
):
|
||||||
await redis.set("TOKEN", "d35d213e-f3d8-4f08-954a-7e0d1bea286f")
|
await redis.set(
|
||||||
|
f"{redis_strategy.key_prefix}TOKEN", "d35d213e-f3d8-4f08-954a-7e0d1bea286f"
|
||||||
|
)
|
||||||
authenticated_user = await redis_strategy.read_token("TOKEN", user_manager)
|
authenticated_user = await redis_strategy.read_token("TOKEN", user_manager)
|
||||||
assert authenticated_user is None
|
assert authenticated_user is None
|
||||||
|
|
||||||
@@ -91,7 +93,7 @@ class TestReadToken:
|
|||||||
user_manager,
|
user_manager,
|
||||||
user,
|
user,
|
||||||
):
|
):
|
||||||
await redis.set("TOKEN", str(user.id))
|
await redis.set(f"{redis_strategy.key_prefix}TOKEN", str(user.id))
|
||||||
authenticated_user = await redis_strategy.read_token("TOKEN", user_manager)
|
authenticated_user = await redis_strategy.read_token("TOKEN", user_manager)
|
||||||
assert authenticated_user is not None
|
assert authenticated_user is not None
|
||||||
assert authenticated_user.id == user.id
|
assert authenticated_user.id == user.id
|
||||||
@@ -104,7 +106,7 @@ async def test_write_token(
|
|||||||
):
|
):
|
||||||
token = await redis_strategy.write_token(user)
|
token = await redis_strategy.write_token(user)
|
||||||
|
|
||||||
value = await redis.get(token)
|
value = await redis.get(f"{redis_strategy.key_prefix}{token}")
|
||||||
assert value == str(user.id)
|
assert value == str(user.id)
|
||||||
|
|
||||||
|
|
||||||
@@ -113,8 +115,8 @@ async def test_write_token(
|
|||||||
async def test_destroy_token(
|
async def test_destroy_token(
|
||||||
redis_strategy: RedisStrategy[UserModel, IDType], redis: RedisMock, user
|
redis_strategy: RedisStrategy[UserModel, IDType], redis: RedisMock, user
|
||||||
):
|
):
|
||||||
await redis.set("TOKEN", str(user.id))
|
await redis.set(f"{redis_strategy.key_prefix}TOKEN", str(user.id))
|
||||||
|
|
||||||
await redis_strategy.destroy_token("TOKEN", user)
|
await redis_strategy.destroy_token("TOKEN", user)
|
||||||
|
|
||||||
assert await redis.get("TOKEN") is None
|
assert await redis.get(f"{redis_strategy.key_prefix}TOKEN") is None
|
||||||
|
|||||||
Reference in New Issue
Block a user