import httpx from fastapi import HTTPException, Depends, Security from fastapi.security import SecurityScopes from httpx import ConnectError from jose import jwt from starlette.requests import Request from config import conf from .model import UserModel, ValidateTokenInput from .schema import oauth2 from ..app_context import use_user from ...service.redis import redis_set, redis_get def decode_token(token: str): return jwt.decode( token.split(' ').pop(), conf.auth.secret_key, algorithms=[conf.auth.algorithm]) async def validate_token(_input: ValidateTokenInput): try: _cache_key = _input.token.split('.')[-1] _cache_auth = await redis_get(f'{conf.auth.cache_prefix_key}{_cache_key}', conf.database.get('auth_redis')) if not _cache_auth: client = httpx.AsyncClient() headers = {'Content-Type': 'application/json', } result = await client.request('POST', conf.auth.url, json=_input.dict(), headers=headers) export = result.text if 'application/json' in result.headers['content-type']: export = result.json() if result.status_code > 299: raise HTTPException(status_code=result.status_code, detail=export) if 'v2' in conf.auth.url: export = export.get('data') await redis_set(f'{conf.auth.cache_prefix_key}{_cache_key}', export, conf.database.get('auth_redis'), ex=conf.auth.cache_ttl) return UserModel(**export) else: return UserModel(**_cache_auth) except ConnectError as e: raise HTTPException(status_code=400, detail=str(e)) except HTTPException as e: raise e except Exception as e: raise HTTPException(status_code=400, detail=str(e)) async def get_current_user(security_scopes: SecurityScopes, token: str = Depends(oauth2)): if security_scopes.scopes: authenticate_value = f'Bearer scope="{security_scopes.scope_str}"' else: authenticate_value = f"Bearer" credentials_exception = HTTPException( status_code=401, detail="Could not validate credentials", headers={"WWW-Authenticate": authenticate_value}, ) user = await validate_token(ValidateTokenInput(token=token, scopes=security_scopes.scopes)) if user is None: raise credentials_exception user.scopes = security_scopes.scopes if isinstance( security_scopes.scopes, list) else security_scopes.scopes return user async def get_current_active_user(request: Request, current_user: UserModel = Security(get_current_user, scopes=["account"]), ): if current_user.disabled: raise HTTPException(status_code=400, detail="Inactive user") request.state.user = UserModel(**current_user.mongo_dict()) use_user(UserModel(**current_user.mongo_dict())) return current_user