update log config for kontor-api
fix double occurances of log output and change level to Debug for Profile information
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
from datetime import timedelta
|
||||
|
||||
from fastapi import APIRouter, HTTPException, status
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -9,6 +10,7 @@ from src.schema.admin import Token
|
||||
|
||||
login_router = APIRouter()
|
||||
|
||||
|
||||
class LoginRequest(BaseModel):
|
||||
email: str | None = None
|
||||
password: str | None = None
|
||||
@@ -19,12 +21,11 @@ class LoginRequest(BaseModel):
|
||||
tags=["login"],
|
||||
summary="Login and get token",
|
||||
response_description="Return HTTP status code 200 (OK)",
|
||||
status_code=status.HTTP_200_OK
|
||||
status_code=status.HTTP_200_OK,
|
||||
)
|
||||
def login(request: LoginRequest) -> Token:
|
||||
logger.info(f"login with {request.email} with {request.password}")
|
||||
print(f"login with {request.email} with {request.password}")
|
||||
user = authenticate_user(request.email, request.password) # type: ignore
|
||||
logger.info(f"login with {request.email}")
|
||||
user = authenticate_user(request.email, request.password) # type: ignore
|
||||
scopes = ["admin", "read"]
|
||||
if not user:
|
||||
raise HTTPException(
|
||||
@@ -33,5 +34,8 @@ def login(request: LoginRequest) -> Token:
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
|
||||
access_token = create_access_token(data={"sub": user.email, "scope": " ".join(scopes)}, expires_delta=access_token_expires)
|
||||
access_token = create_access_token(
|
||||
data={"sub": user.email, "scope": " ".join(scopes)},
|
||||
expires_delta=access_token_expires,
|
||||
)
|
||||
return Token(access_token=access_token, token_type="bearer")
|
||||
|
||||
@@ -8,15 +8,15 @@ LOGGING_CONFIG: dict[str, Any] = {
|
||||
"formatters": {
|
||||
"default": {
|
||||
"()": "uvicorn.logging.DefaultFormatter",
|
||||
"fmt": "%(asctime)s - %(name)s - %(levelprefix)s %(message)s"
|
||||
"fmt": "%(asctime)s - %(name)s - %(levelprefix)s %(message)s",
|
||||
},
|
||||
"access": {
|
||||
"()": "uvicorn.logging.AccessFormatter",
|
||||
"fmt": '%(asctime)s - %(name)s - %(levelprefix)s %(client_addr)s - "%(request_line)s" %(status_code)s', # noqa: E501
|
||||
"fmt": '%(asctime)s - %(name)s - %(levelprefix)s %(client_addr)s - "%(request_line)s" %(status_code)s', # noqa: E501
|
||||
},
|
||||
"access_file": {
|
||||
"()": "uvicorn.logging.AccessFormatter",
|
||||
"fmt": '%(asctime)s - %(name)s - %(levelprefix)s %(client_addr)s - "%(request_line)s" %(status_code)s', # noqa: E501
|
||||
"fmt": '%(asctime)s - %(name)s - %(levelprefix)s %(client_addr)s - "%(request_line)s" %(status_code)s', # noqa: E501
|
||||
"use_colors": False,
|
||||
},
|
||||
},
|
||||
@@ -34,12 +34,16 @@ LOGGING_CONFIG: dict[str, Any] = {
|
||||
},
|
||||
"loggers": {
|
||||
"root": {"handlers": ["default"], "level": "INFO", "propagate": False},
|
||||
"kontor": {"handlers": ["default"], "level": "INFO", "propagate": True},
|
||||
"kontor": {"handlers": ["default"], "level": "INFO", "propagate": False},
|
||||
"uvicorn": {"handlers": ["default"], "level": "INFO", "propagate": False},
|
||||
"uvicorn.error": {"level": "INFO"},
|
||||
"uvicorn.access": {"handlers": ["default"], "level": "WARNING", "propagate": False},
|
||||
"uvicorn.access": {
|
||||
"handlers": ["default"],
|
||||
"level": "WARNING",
|
||||
"propagate": False,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
logging.config.dictConfig(LOGGING_CONFIG)
|
||||
logger = logging.getLogger('kontor')
|
||||
logger = logging.getLogger("kontor")
|
||||
|
||||
@@ -1,29 +1,21 @@
|
||||
import logging
|
||||
from datetime import datetime, timezone
|
||||
from datetime import timedelta
|
||||
from typing import Optional, Annotated, List
|
||||
from typing import Dict
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import HTTPException, Security
|
||||
from fastapi import Request
|
||||
from fastapi import status
|
||||
from fastapi.openapi.models import OAuthFlows as OAuthFlowsModel
|
||||
from fastapi.security.utils import get_authorization_scheme_param
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from typing import Annotated, Dict, List, Optional
|
||||
|
||||
import bcrypt
|
||||
from fastapi import Depends
|
||||
from fastapi.security import SecurityScopes, OAuth2PasswordBearer, OAuth2
|
||||
from fastapi import Depends, HTTPException, Request, Security, status
|
||||
from fastapi.openapi.models import OAuthFlows as OAuthFlowsModel
|
||||
from fastapi.security import OAuth2, OAuth2PasswordBearer, SecurityScopes
|
||||
from fastapi.security.utils import get_authorization_scheme_param
|
||||
from jose import JWTError, jwt
|
||||
from pydantic import ValidationError
|
||||
|
||||
from src.core.config import settings
|
||||
from jose import jwt, JWTError
|
||||
|
||||
from src.core.log_conf import logger
|
||||
from src.db.models.admin import Profile
|
||||
from src.db.repository.admin import get_profile
|
||||
from src.db.session import SessionLocal
|
||||
from src.schema.admin import TokenData, ProfileModel
|
||||
from src.schema.admin import ProfileModel, TokenData
|
||||
|
||||
oauth2_scheme = OAuth2PasswordBearer(
|
||||
tokenUrl="/api/login/token",
|
||||
@@ -33,15 +25,15 @@ oauth2_scheme = OAuth2PasswordBearer(
|
||||
|
||||
class OAuth2PasswordBearerWithCookie(OAuth2):
|
||||
def __init__(
|
||||
self,
|
||||
tokenUrl: str,
|
||||
scheme_name: Optional[str] = None,
|
||||
scopes: Optional[Dict[str, str]] = None,
|
||||
auto_error: bool = True,
|
||||
self,
|
||||
tokenUrl: str,
|
||||
scheme_name: Optional[str] = None,
|
||||
scopes: Optional[Dict[str, str]] = None,
|
||||
auto_error: bool = True,
|
||||
):
|
||||
if not scopes:
|
||||
scopes = {}
|
||||
flows = OAuthFlowsModel(password={"tokenUrl": tokenUrl, "scopes": scopes}) # type: ignore
|
||||
flows = OAuthFlowsModel(password={"tokenUrl": tokenUrl, "scopes": scopes}) # type: ignore
|
||||
super().__init__(flows=flows, scheme_name=scheme_name, auto_error=auto_error)
|
||||
|
||||
async def __call__(self, request: Request) -> Optional[str]:
|
||||
@@ -63,7 +55,7 @@ class OAuth2PasswordBearerWithCookie(OAuth2):
|
||||
def authenticate_user(username: str, password: str) -> Optional[Profile]:
|
||||
with SessionLocal() as db:
|
||||
user = get_profile(username=username, db=db)
|
||||
logger.info(user)
|
||||
logger.debug(user)
|
||||
if not user:
|
||||
return None
|
||||
if bcrypt.checkpw(password.encode(), user.password.encode()):
|
||||
@@ -88,7 +80,9 @@ def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
|
||||
return encoded_jwt
|
||||
|
||||
|
||||
async def get_current_user(security_scopes: SecurityScopes, token: Annotated[str, Depends(oauth2_scheme)]):
|
||||
async def get_current_user(
|
||||
security_scopes: SecurityScopes, token: Annotated[str, Depends(oauth2_scheme)]
|
||||
):
|
||||
if security_scopes.scopes:
|
||||
authenticate_value = f'Bearer scope="{security_scopes.scope_str}"'
|
||||
else:
|
||||
@@ -99,8 +93,10 @@ async def get_current_user(security_scopes: SecurityScopes, token: Annotated[str
|
||||
headers={"WWW-Authenticate": authenticate_value},
|
||||
)
|
||||
try:
|
||||
payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM])
|
||||
username: str = payload.get("sub") # type: ignore
|
||||
payload = jwt.decode(
|
||||
token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM]
|
||||
)
|
||||
username: str = payload.get("sub") # type: ignore
|
||||
logger.info("username/email extracted is ", username)
|
||||
if username is None:
|
||||
raise credentials_exception
|
||||
@@ -110,7 +106,7 @@ async def get_current_user(security_scopes: SecurityScopes, token: Annotated[str
|
||||
except (JWTError, ValidationError):
|
||||
raise credentials_exception
|
||||
with SessionLocal() as db:
|
||||
user = get_profile(username=token_data.username, db=db) # type: ignore
|
||||
user = get_profile(username=token_data.username, db=db) # type: ignore
|
||||
if user is None:
|
||||
raise credentials_exception
|
||||
for scope in security_scopes.scopes:
|
||||
@@ -124,17 +120,20 @@ async def get_current_user(security_scopes: SecurityScopes, token: Annotated[str
|
||||
|
||||
|
||||
async def get_current_active_user(
|
||||
current_user: Annotated[Profile, Security(get_current_user, scopes=["me"])],
|
||||
current_user: Annotated[Profile, Security(get_current_user, scopes=["me"])],
|
||||
) -> ProfileModel:
|
||||
if not current_user.enabled: # type: ignore
|
||||
if not current_user.enabled: # type: ignore
|
||||
raise HTTPException(status_code=400, detail="Inactive user")
|
||||
user_model = ProfileModel(username=current_user.user_name, email=current_user.email, # type: ignore
|
||||
first_name=current_user.first_name, last_name=current_user.last_name, # type: ignore
|
||||
active=current_user.enabled) # type: ignore
|
||||
user_model = ProfileModel(
|
||||
username=current_user.user_name,
|
||||
email=current_user.email, # type: ignore
|
||||
first_name=current_user.first_name,
|
||||
last_name=current_user.last_name, # type: ignore
|
||||
active=current_user.enabled,
|
||||
) # type: ignore
|
||||
return user_model
|
||||
|
||||
|
||||
|
||||
def get_current_user_from_token(token: str = Depends(oauth2_scheme)):
|
||||
credentials_exception = HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
@@ -144,7 +143,7 @@ def get_current_user_from_token(token: str = Depends(oauth2_scheme)):
|
||||
payload = jwt.decode(
|
||||
token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM]
|
||||
)
|
||||
username: str = payload.get("sub") # type: ignore
|
||||
username: str = payload.get("sub") # type: ignore
|
||||
logger.info("username/email extracted is ", username)
|
||||
if username is None:
|
||||
raise credentials_exception
|
||||
|
||||
Reference in New Issue
Block a user