Skip to content

Commit

Permalink
add optional redis module
Browse files Browse the repository at this point in the history
use redis to store scopes of an issued transaction token
  • Loading branch information
mstingl committed Aug 3, 2023
1 parent 45aca67 commit 4e1cdc7
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 4 deletions.
6 changes: 5 additions & 1 deletion djfapi/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
from .user import AbstractUserTokenMixin, AbstractUserRefreshTokenMixin, AbstractUserTransactionTokenMixin
from .user import (
AbstractUserTokenMixin,
AbstractUserRefreshTokenMixin,
AbstractUserTransactionTokenMixin,
)
9 changes: 7 additions & 2 deletions djfapi/models/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@


class AbstractUserTokenMixin(models.Model):
def _save_user_token(self, token_id):
def _save_user_token(self, token_id: str):
raise NotImplementedError

def _save_transaction_token(self, token_id: str):
return

def _get_user_token(self, token_id: str):
raise NotImplementedError

Expand Down Expand Up @@ -73,12 +76,14 @@ def create_transaction_token(self, include_critical: bool = False, used_token: O
if used_token:
self._get_user_token(used_token.jti)

token, _ = self._create_token(
token, token_id = self._create_token(
validity=timedelta(minutes=5),
audiences=audiences,
include_critical=include_critical,
)

self._save_transaction_token(token_id)

return token

def create_user_token(self) -> str:
Expand Down
1 change: 1 addition & 0 deletions djfapi/redis/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import security, utils, models
14 changes: 14 additions & 0 deletions djfapi/redis/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from .utils import get_connection


class AbstractUserTransactionTokenDjangoPermissions2RedisMixin:
redis_url = None
redis = None

def _save_transaction_token(self, token_id: str):
if not self.redis:
self.redis = get_connection(self.redis_url)

key = f'access:token:{token_id}:scopes'
self.redis.sadd(key, *self.get_all_permissions())
self.redis.expire(key, int(timedelta(minutes=5).total_seconds()))
1 change: 1 addition & 0 deletions djfapi/redis/security/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import jwt
15 changes: 15 additions & 0 deletions djfapi/redis/security/jwt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from typing import Optional
from djfapi.security.jwt import JWTToken
from ..utils import get_connection


class JWTTokenRedis(JWTToken):
def __init__(self, *args, redis_url: Optional[str] = None, **kwargs):
super().__init__(*args, **kwargs)
self.redis = get_connection(redis_url, use_async=True)

async def _create_access(self, token):
access = await super()._create_access(token)
scopes = await self.redis.smembers(f'access:token:{access.jti}:scopes')
access.token.aud = [str(scope, 'utf-8') for scope in scopes]
return access
29 changes: 29 additions & 0 deletions djfapi/redis/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from typing import Optional
from django.conf import settings
from redis.asyncio import Redis as RedisAsync, RedisCluster as RedisAsyncCluster
from redis import Redis, RedisCluster


CONNECTIONS = {}


def get_connection(
redis_url: Optional[str] = None, use_async: bool = False, is_cluster: Optional[bool] = None
) -> 'Redis':
if is_cluster is None:
is_cluster = getattr(settings, 'REDIS_IS_CLUSTER', False)

if use_async:
R = RedisAsyncCluster if is_cluster else RedisAsync

else:
R = RedisCluster if is_cluster else Redis

redis_url = redis_url or getattr(settings, 'REDIS_URL', None) or 'redis://localhost:6379/0'

try:
return CONNECTIONS[(redis_url, use_async)]

except KeyError:
CONNECTIONS[(redis_url, use_async)] = R.from_url(redis_url)
return CONNECTIONS[(redis_url, use_async)]
6 changes: 5 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[metadata]
name = djfapi
version = 0.0.64
version = 0.0.65
author = Manuel Stingl
author_email = opensource@voltane.eu
description = Utilities for use with FastAPI and django
Expand Down Expand Up @@ -28,3 +28,7 @@ install_requires =
django-health-check >= 3.16
python-forge
langcodes

[options.extras_require]
redis =
redis

0 comments on commit 4e1cdc7

Please sign in to comment.