api: improvements, storage users as dependency

This commit is contained in:
Helmut Merz 2026-11-09 08:34:33 +01:00
parent a139fd784e
commit 8963c2ac87
4 changed files with 23 additions and 18 deletions

View file

@ -9,7 +9,7 @@ class Settings(BaseSettings):
#, env_prefix='SCOPES_') #, env_prefix='SCOPES_')
auth_method: str = 'oauth2' auth_method: str = 'oauth2'
jwt_key: str | None = None jwt_key: str | None = None
jwt_atlgorithm: str = 'HS256' jwt_algorithm: str = 'HS256'
settings = Settings() settings = Settings()

View file

@ -24,7 +24,7 @@ class User(UserBase):
timeStamp: datetime | None = None timeStamp: datetime | None = None
pw_hash: str | None = Field(exclude=True, default=None) pw_hash: str | None = Field(exclude=True, default=None)
class UserIn(UserBase): class UserEdit(UserBase):
password: str | None = None password: str | None = None
def hashPassword(self) -> str | None: def hashPassword(self) -> str | None:
@ -41,15 +41,10 @@ def hashPassword(pw):
def verifyPassword(plain, hashed): def verifyPassword(plain, hashed):
return pw_hash.verify(plain, hashed) return pw_hash.verify(plain, hashed)
def getUser(storage: Storage, userName: str) -> User: def userFromToken(users: deps.Users, token: deps.AuthToken):
users = storage.create(st_user.Users)
user = users.queryLast(name=userName)
return user.toObject(User)
async def authenticate(storage: deps.Storage, token: deps.AuthUser):
payload = jwt.decode(token, settings.jwt_key, algorithms=[settings.jwt_algorithm]) payload = jwt.decode(token, settings.jwt_key, algorithms=[settings.jwt_algorithm])
userName = payload.get('sub') userName = payload.get('sub')
user = getUser(storage, userName) user = users.queryLast(name=userName)
return user return user
# routes # routes
@ -57,16 +52,14 @@ async def authenticate(storage: deps.Storage, token: deps.AuthUser):
router = APIRouter() router = APIRouter()
@router.get('/users', response_model=list[User]) @router.get('/users', response_model=list[User])
async def get_users(storage: deps.Storage): async def get_users(users: deps.Users):
users = storage.create(st_user.Users)
result = [tr.toObject(User) for tr in users.query()] result = [tr.toObject(User) for tr in users.query()]
return result return result
@router.post('/users', response_model=User) @router.post('/users', response_model=User)
async def post_user(user: Annotated[UserIn, Body()], storage: deps.Storage, async def post_user(user: Annotated[UserEdit, Body()], users: deps.Users,
auth_user: deps.AuthUser): auth_user: deps.AuthUser):
print('*** post_user', auth_user) print('*** post_user', auth_user)
users = storage.create(st_user.Users)
tr = st_user.User.fromObject(user) tr = st_user.User.fromObject(user)
users.save(tr) users.save(tr)
return tr.toObject(User) return tr.toObject(User)

View file

@ -8,16 +8,30 @@ from typing import Annotated
from scopes import config from scopes import config
from scopes.api.auth import config as auth_config from scopes.api.auth import config as auth_config
from scopes.storage import common from scopes.storage import common
from scopes.storage import user as st_user
type Storage = Annotated[common.Storage, Depends(storage)] type Storage = Annotated[common.Storage, Depends(storage)]
type Users = Annotated[st_user.Users, Depends(users)]
type AuthUser = Annotated[str, Depends(auth_user)] type AuthUser = Annotated[str, Depends(auth_user)]
type AuthToken = Annotated[str, Depends(auth_token)]
# storage
def storage(): def storage():
stf = config.StorageFactory(config.settings) stf = config.StorageFactory(config.settings)
return stf(config.settings.dbschema) return stf(config.settings.dbschema)
def users(storage: Storage):
return storage.create(st_user.Users)
# auth
def auth_user(): def auth_user():
auth = auth_config.auth_methods.get(auth_config.settings.auth_method) auth = auth_config.auth_methods.get(auth_config.settings.auth_method)
if auth: if auth is not None:
return auth() return auth()
def auth_token():
return None

View file

@ -3,21 +3,19 @@
"""Tests for the fastapi- (and asyncio-) based stuff""" """Tests for the fastapi- (and asyncio-) based stuff"""
from scopes import config from scopes import config
from scopes.api.auth import config as auth_config
config.settings = config.Settings(_env_file='tests/test.env') config.settings = config.Settings(_env_file='tests/test.env')
auth_config.settings = auth_config.Settings(_env_file='tests/test.env')
import pytest import pytest
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from httpx2 import ASGITransport, AsyncClient, BasicAuth from httpx2 import ASGITransport, AsyncClient, BasicAuth
from scopes.api import main from scopes.api import main
from scopes.api.auth import config as auth_config
from scopes.api.main import app from scopes.api.main import app
from scopes.storage import tracking, user as st_user from scopes.storage import tracking, user as st_user
from scopes.api.auth import user as api_user from scopes.api.auth import user as api_user
config.settings = config.Settings(_env_file='tests/test.env')
auth_config.settings = auth_config.Settings(_env_file='tests/test.env')
@pytest.fixture(scope='module') @pytest.fixture(scope='module')
def storage(): def storage():
storage = config.StorageFactory(config.settings)(config.settings.dbschema) storage = config.StorageFactory(config.settings)(config.settings.dbschema)