Merge branch 'dev3' into dev2

This commit is contained in:
2025-03-04 16:53:41 +09:00
47 changed files with 314 additions and 277 deletions

View File

@@ -46,6 +46,9 @@ async def login(request: Request,db:Session= Depends(get_db) ,form_data: OAuth2P
data={"sub": user.id,"roles":roles,"permissions": permissions,"tenant":user.tenantid,},
expires_delta=access_token_expires,
)
request.state.user = user.id
return JSONResponse(
status_code=200,
content={"access_token": access_token, "token_type": "bearer","user_name":user.first_name + " " + user.last_name}

View File

@@ -9,7 +9,7 @@ from app.core import security
from app.db.cruddb import userService
from app.core.dbmanager import get_db
async def get_current_user(security_scopes: SecurityScopes,
async def get_current_user(request: Request,security_scopes: SecurityScopes,
db=Depends(get_db), token: str = Depends(security.oauth2_scheme)
):
credentials_exception = HTTPException(
@@ -42,6 +42,7 @@ async def get_current_user(security_scopes: SecurityScopes,
user = userService.get_user(db, token_data.id)
if user is None:
raise credentials_exception
request.state.user = user.id
return user
async def get_current_active_user(

View File

@@ -1,8 +1,8 @@
import time
from typing import Any
from sqlalchemy.orm import Session
from app.db.cruddb import domainService
from app.db.cruddb import tenantService
from app.db.cruddb import domainService,tenantService
from app.db.session import Database
class MemoryCache:
def __init__(self, max_cache_size: int = 100, ttl: int = 60):
@@ -60,12 +60,13 @@ class tenantCache:
def __init__(self):
self.memoryCache = MemoryCache(max_cache_size=50, ttl=120)
def get_tenant_db(self,db: Session, tenantid: str):
if not self.memoryCache.get(f"TENANT_{tenantid}"):
tenant = tenantService.get_tenant(db,tenantid)
if tenant:
self.memoryCache.set(f"TENANT_{tenantid}",tenant.db)
return self.memoryCache.get(f"TENANT_{tenantid}")
database = Database(tenant.db)
self.memoryCache.set(f"TENANT_{tenantid}",database)
return self.memoryCache.get(f"TENANT_{tenantid}")
tenantCacheService =tenantCache()

View File

@@ -1,13 +1,15 @@
from fastapi import Depends
from app.db.session import get_tenant_db,get_user_db
from fastapi import Depends,Request
from app.db.session import get_tenant_db
from app.core import tenantCacheService
from app.db.session import tenantdb
def get_db(tenant:str = "1",tenantdb = Depends(get_tenant_db)):
db_url = tenantCacheService.get_tenant_db(tenantdb,tenant)
db = get_user_db(db_url)
def get_db(request: Request,tenant:str = "1",tenantdb = Depends(get_tenant_db)):
database = tenantCacheService.get_tenant_db(tenantdb,tenant)
try:
db = database.get_db()
request.state.tenant = tenant
request.state.db = db
yield db
finally:
db.close()

View File

@@ -1,52 +1,75 @@
from fastapi import Request
from fastapi.responses import JSONResponse
from starlette.middleware.base import BaseHTTPMiddleware
from sqlalchemy.orm import Session
from app.db.models import OperationLog,User
from app.core.apiexception import APIException
from app.core.dbmanager import get_log_db
from app.db.crud import create_log
import json
from functools import wraps
from fastapi import Request
class LoggingMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
if request.method in ("POST", "PUT", "PATCH","DELETE"):
try:
request.state.body = await request.json()
except json.JSONDecodeError:
request.state.body = await request.body()
else:
request.state.body = None
def log_operation(func):
"""自定义装饰器用于记录操作日志"""
@wraps(func)
async def wrapper(*args, **kwargs):
if 'request' in kwargs and isinstance(kwargs['request'], Request):
request: Request = kwargs['request']
method = request.method
url = str(request.url)
client_ip = request.client.host
headers = dict(request.headers)
user_agent = headers.get("user-agent", "")
if 'db' in kwargs and isinstance(kwargs['db'], Session):
db = kwargs['db']
if 'user' in kwargs and isinstance(kwargs['user'], User):
user = kwargs['user']
user_id = user.id
tenant_id = user.tenantid
else:
user_id = None
tenant_id = None
try:
response = await func(*args, **kwargs)
if db:
db_operation = OperationLog(tenantid =tenant_id,
clientip =client_ip,
useragent =user_agent,
userid = user_id,
operation = method,
function = url,
response = f"status_code:{response.status_code }" )
db.add(db_operation)
db.commit()
response = await call_next(request)
state = request.state
except Exception as e:
raise e
return response
return wrapper
await self.log_error(request, e)
response = JSONResponse(
content={"detail": "Internal Server Error"},
status_code=500
)
if hasattr(request.state, "user") and hasattr(request.state, "tenant"):
await self.log_request(request, response,state)
return response
async def log_request(self, request: Request, response,state):
try:
headers = dict(request.headers)
route = request.scope.get("route")
if route:
path_template = route.path
else:
path_template = request.url.path
db_operation = OperationLog(tenantid =request.state.tenant,
clientip = request.client.host if request.client else None,
useragent =headers.get("user-agent", ""),
userid = request.state.user,
operation = request.method,
function = path_template,
parameters = str({"path": request.path_params,"query": dict(request.query_params),"body": request.state.body}),
response = f"status_code:{response.status_code }" )
db = request.state.db
if db:
await self.write_log_to_db(db_operation,db)
except Exception as e:
print(f"Logging failed: {str(e)}")
async def log_error(self, request: Request, e: Exception):
exc = APIException('operation:dispatch',request.url._url,f"Error occurred while writting operation log:",e)
db = get_log_db()
try:
create_log(db,exc.error)
finally:
db.close()
async def write_log_to_db(self, db_operation,db):
db.add(db_operation)
db.commit()

View File

@@ -1,14 +1,14 @@
from sqlalchemy import Boolean, Column, Integer, String, DateTime,ForeignKey,Table
from sqlalchemy.orm import Mapped,relationship,as_declarative,mapped_column
from datetime import datetime
from datetime import datetime,timezone
from app.db import Base
from app.core.security import chacha20Decrypt
@as_declarative()
class Base:
id = Column(Integer, primary_key=True, index=True)
create_time = Column(DateTime, default=datetime.now)
update_time = Column(DateTime, default=datetime.now, onupdate=datetime.now)
create_time = Column(DateTime, default=datetime.now(timezone.utc))
update_time = Column(DateTime, default=datetime.now(timezone.utc), onupdate=datetime.now(timezone.utc))
userrole = Table(
@@ -234,6 +234,7 @@ class OperationLog(Base):
userid = mapped_column(Integer,ForeignKey("user.id"))
operation = mapped_column(String(200))
function = mapped_column(String(200))
parameters = mapped_column(String(200))
response = mapped_column(String(200))
user = relationship('User')

View File

@@ -20,7 +20,7 @@ from app.db.crud import create_log
from fastapi.responses import JSONResponse
import asyncio
from contextlib import asynccontextmanager
from app.core.operation import LoggingMiddleware
#Base.metadata.create_all(bind=engine)
@@ -45,6 +45,8 @@ app.add_middleware(
allow_headers=["*"],
)
app.add_middleware(LoggingMiddleware)
add_pagination(app)
# @app.middleware("http")