refactor: 重构Redis依赖注入以提升代码可维护性

将Redis依赖从Request对象中解耦,改为通过Depends注入,提高代码的可测试性和可维护性
This commit is contained in:
zhangtao
2025-04-15 04:25:07 +08:00
parent da957dca55
commit 7892121066
15 changed files with 160 additions and 136 deletions
@@ -1,9 +1,10 @@
# -*- coding: utf-8 -*-
from fastapi import APIRouter, Depends, Request
from fastapi import APIRouter, Depends
from fastapi.responses import JSONResponse
from aioredis import Redis
from app.core.dependencies import AuthPermission
from app.core.dependencies import AuthPermission, redis_getter
from app.api.v1.services.monitor.cache_service import CacheService
from app.core.logger import logger
from app.common.response import SuccessResponse
@@ -20,9 +21,11 @@ router = APIRouter(route_class=OperationLogRoute)
summary="获取缓存监控信息",
description="获取缓存监控信息"
)
async def get_monitor_cache_info_controller(request: Request) -> JSONResponse:
async def get_monitor_cache_info_controller(
redis: Redis = Depends(redis_getter)
) -> JSONResponse:
"""获取缓存监控统计信息"""
result = await CacheService.get_cache_monitor_statistical_info_service(request)
result = await CacheService.get_cache_monitor_statistical_info_service(redis=redis)
logger.info('获取缓存监控信息成功')
return SuccessResponse(data=result, msg='获取缓存监控信息成功')
@@ -46,9 +49,12 @@ async def get_monitor_cache_name_controller() -> JSONResponse:
summary="获取缓存键名列表",
description="获取缓存键名列表"
)
async def get_monitor_cache_key_controller(request: Request, cache_name: str) -> JSONResponse:
async def get_monitor_cache_key_controller(
cache_name: str,
redis: Redis = Depends(redis_getter)
) -> JSONResponse:
"""获取指定缓存名称下的键名列表"""
result = await CacheService.get_cache_monitor_cache_key_service(request, cache_name)
result = await CacheService.get_cache_monitor_cache_key_service(redis=redis, cache_name=cache_name)
logger.info(f'获取缓存{cache_name}的键名列表成功')
return SuccessResponse(data=result, msg=f'获取缓存{cache_name}的键名列表成功')
@@ -59,9 +65,13 @@ async def get_monitor_cache_key_controller(request: Request, cache_name: str) ->
summary="获取缓存值",
description="获取缓存值"
)
async def get_monitor_cache_value_controller(request: Request, cache_name: str, cache_key: str) -> JSONResponse:
async def get_monitor_cache_value_controller(
cache_name: str,
cache_key: str,
redis: Redis = Depends(redis_getter)
)-> JSONResponse:
"""获取指定缓存键的值"""
result = await CacheService.get_cache_monitor_cache_value_service(request, cache_name, cache_key)
result = await CacheService.get_cache_monitor_cache_value_service(redis=redis, cache_name=cache_name, cache_key=cache_key)
logger.info(f'获取缓存{cache_name}:{cache_key}的值成功')
return SuccessResponse(data=result, msg=f'获取缓存{cache_name}:{cache_key}的值成功')
@@ -72,9 +82,12 @@ async def get_monitor_cache_value_controller(request: Request, cache_name: str,
summary="清除指定缓存名称的所有缓存",
description="清除指定缓存名称的所有缓存"
)
async def clear_monitor_cache_name_controller(request: Request, cache_name: str) -> JSONResponse:
async def clear_monitor_cache_name_controller(
cache_name: str,
redis: Redis = Depends(redis_getter)
) -> JSONResponse:
"""清除指定缓存名称下的所有缓存"""
result = await CacheService.clear_cache_monitor_cache_name_service(request, cache_name)
result = await CacheService.clear_cache_monitor_cache_name_service(redis=redis, cache_name=cache_name)
if not result:
raise CustomException(message='清除缓存失败', data=result)
logger.info(f'清除缓存{cache_name}成功')
@@ -87,9 +100,12 @@ async def clear_monitor_cache_name_controller(request: Request, cache_name: str)
summary="清除指定缓存键",
description="清除指定缓存键"
)
async def clear_monitor_cache_key_controller(request: Request, cache_key: str) -> JSONResponse:
async def clear_monitor_cache_key_controller(
cache_key: str,
redis: Redis = Depends(redis_getter)
) -> JSONResponse:
"""清除指定缓存键"""
result = await CacheService.clear_cache_monitor_cache_key_service(request, cache_key)
result = await CacheService.clear_cache_monitor_cache_key_service(redis=redis, cache_key=cache_key)
if not result:
raise CustomException(message='清除缓存失败', data=result)
logger.info(f'清除缓存键{cache_key}成功')
@@ -102,9 +118,11 @@ async def clear_monitor_cache_key_controller(request: Request, cache_key: str) -
summary="清除所有缓存",
description="清除所有缓存"
)
async def clear_monitor_cache_all_controller(request: Request) -> JSONResponse:
async def clear_monitor_cache_all_controller(
redis: Redis = Depends(redis_getter)
) -> JSONResponse:
"""清除所有缓存"""
result = await CacheService.clear_cache_monitor_all_service(request)
result = await CacheService.clear_cache_monitor_all_service(redis=redis)
if not result:
raise CustomException(message='清除缓存失败', data=result)
logger.info('清除所有缓存成功')
@@ -1,9 +1,10 @@
# -*- coding: utf-8 -*-
from fastapi import APIRouter, Body, Depends, Request
from fastapi import APIRouter, Body, Depends
from fastapi.responses import JSONResponse
from aioredis import Redis
from app.core.dependencies import AuthPermission
from app.core.dependencies import AuthPermission, redis_getter
from app.core.logger import logger
from app.common.request import PaginationService
from app.common.response import SuccessResponse,ErrorResponse
@@ -23,12 +24,12 @@ router = APIRouter(route_class=OperationLogRoute)
description="获取在线用户列表"
)
async def get_online_list_controller(
request: Request,
redis: Redis = Depends(redis_getter),
paging_query: PaginationQueryParams = Depends(),
search: OnlineQueryParams = Depends()
)->JSONResponse:
# 获取全量数据
result_dict_list = await OnlineService.get_online_list_service(request=request, search=search)
result_dict_list = await OnlineService.get_online_list_service(redis=redis, search=search)
result_dict = await PaginationService.get_page_obj(data_list= result_dict_list, page_no= paging_query.page_no, page_size = paging_query.page_size)
logger.info('获取成功')
@@ -42,10 +43,10 @@ async def get_online_list_controller(
description="强制下线"
)
async def delete__online_controller(
request: Request,
redis: Redis = Depends(redis_getter),
username: str = Body(..., description="用户"),
)->JSONResponse:
delete_online_result = await OnlineService.delete_online_service(request=request, username=username)
delete_online_result = await OnlineService.delete_online_service(redis=redis, username=username)
if delete_online_result:
logger.info("强制下线成功")
return SuccessResponse(msg="强制下线成功")
@@ -5,6 +5,7 @@ from typing import Union, Dict
from fastapi import APIRouter, Depends, Request, BackgroundTasks, WebSocket
from fastapi.responses import JSONResponse, StreamingResponse
from sqlalchemy.ext.asyncio import AsyncSession
from aioredis import Redis
from app.config.setting import settings
from app.common.response import ErrorResponse, SuccessResponse
@@ -20,7 +21,8 @@ from app.api.v1.schemas.system.auth_schema import (
)
from app.core.dependencies import (
db_getter,
get_current_user
get_current_user,
redis_getter
)
from app.core.router_class import OperationLogRoute
from app.core.security import CustomOAuth2PasswordRequestForm
@@ -33,11 +35,12 @@ router = APIRouter(route_class=OperationLogRoute)
@router.post("/login", summary="登录", description="登录", response_model=JWTOutSchema)
async def login_for_access_token_controller(
request: Request,
redis: Redis = Depends(redis_getter),
login_form: CustomOAuth2PasswordRequestForm = Depends(),
db: AsyncSession = Depends(db_getter),
) -> Union[JSONResponse, Dict]:
user = await LoginService.authenticate_user_service(request=request, login_form=login_form, db=db)
login_token = await LoginService.create_token_service(request=request, username=user.username)
user = await LoginService.authenticate_user_service(request=request, redis=redis, login_form=login_form, db=db)
login_token = await LoginService.create_token_service(redis=redis, username=user.username)
logger.info(f"用户{user.username}登录成功")
# 如果是文档请求,则不记录日志:http://localhost:8000/api/v1/docs
@@ -48,11 +51,11 @@ async def login_for_access_token_controller(
@router.post("/token/refresh", summary="刷新token", description="刷新token", response_model=JWTOutSchema, dependencies=[Depends(get_current_user)])
async def get_new_token_controller(
request: Request,
payload: RefreshTokenPayloadSchema
payload: RefreshTokenPayloadSchema,
redis: Redis = Depends(redis_getter)
) -> JSONResponse:
# 解析当前的访问Token以获取用户名
new_token = await LoginService.refresh_token_service(request=request, refresh_token=payload)
new_token = await LoginService.refresh_token_service(redis=redis, refresh_token=payload)
token_dict = new_token.model_dump()
logger.info(f"刷新token成功: {token_dict}")
return SuccessResponse(data=token_dict, msg="刷新成功")
@@ -60,20 +63,20 @@ async def get_new_token_controller(
@router.post("/captcha/get", summary="获取验证码", description="获取登录验证码", response_model=CaptchaOutSchema)
async def get_captcha_for_login_controller(
request: Request
redis: Redis = Depends(redis_getter)
) -> JSONResponse:
# 获取验证码
captcha = await CaptchaService.get_captcha_service(request=request)
captcha = await CaptchaService.get_captcha_service(redis=redis)
logger.info(f"获取验证码成功")
return SuccessResponse(data=captcha, msg="获取验证码成功")
@router.post('/logout', summary="退出登录", description="退出登录", dependencies=[Depends(get_current_user)])
async def logout_controller(
request: Request,
payload: LogoutPayloadSchema
payload: LogoutPayloadSchema,
redis: Redis = Depends(redis_getter)
) -> JSONResponse:
if await LoginService.logout_services_service(request=request, token=payload):
if await LoginService.logout_services_service(redis=redis, token=payload):
logger.info('退出成功')
return SuccessResponse(msg='退出成功')
return ErrorResponse(msg='退出失败')
@@ -2,9 +2,10 @@
from fastapi import APIRouter, Depends, Request, UploadFile
from fastapi.responses import JSONResponse
from aioredis import Redis
from app.common.response import SuccessResponse
from app.core.dependencies import AuthPermission
from app.core.dependencies import AuthPermission, redis_getter
from app.core.router_class import OperationLogRoute
from app.core.logger import logger
from app.api.v1.schemas.system.auth_schema import AuthSchema
@@ -26,11 +27,11 @@ async def get_obj_list_controller(
@router.put("/update", summary="修改配置", description="修改配置")
async def update_objs_controller(
request: Request,
data: ConfigUpdateSchema,
redis: Redis = Depends(redis_getter),
auth: AuthSchema = Depends(AuthPermission(permissions=["system:config:update"]))
) -> JSONResponse:
result_dict = await ConfigService.update_service(auth=auth, request=request, data=data)
result_dict = await ConfigService.update_service(auth=auth, redis=redis, data=data)
logger.info(f"{auth.user.name} 更新配置成功 {result_dict}")
return SuccessResponse(data=result_dict, msg="更新配置成功")
@@ -40,15 +41,15 @@ async def upload_file_controller(
file: UploadFile,
request: Request
) -> JSONResponse:
result_str = await ConfigService.upload_service(request=request, file=file)
result_str = await ConfigService.upload_service(base_url=str(request.base_url), file=file)
logger.info(f"上传文件: {result_str}")
return SuccessResponse(data=result_str, msg='上传文件成功')
@router.get("/init", summary="获取初始化配置", description="获取初始化配置")
async def get_init_config_controller(
request: Request
redis: Redis = Depends(redis_getter)
) -> JSONResponse:
result_dict = await ConfigService.get_init_config_service(request=request)
result_dict = await ConfigService.get_init_config_service(redis=redis)
logger.info(f"获取初始化配置成功 {result_dict}")
return SuccessResponse(data=result_dict, msg="获取初始化配置成功")
@@ -1,13 +1,13 @@
# -*- coding: utf-8 -*-
import json
from fastapi import APIRouter, Depends, Query, Request
from fastapi import APIRouter, Depends, Query
from fastapi.responses import JSONResponse, StreamingResponse
from aioredis import Redis
from app.common.response import StreamResponse, SuccessResponse
from app.core.base_params import PaginationQueryParams
from app.core.dependencies import AuthPermission
from app.core.dependencies import AuthPermission, redis_getter
from app.core.router_class import OperationLogRoute
from app.core.logger import logger
from app.common.request import PaginationService
@@ -55,31 +55,31 @@ async def get_type_list_controller(
@router.post("/type/create", summary="创建字典类型", description="创建字典类型")
async def create_type_controller(
request: Request,
data: DictTypeCreateSchema,
redis: Redis = Depends(redis_getter),
auth: AuthSchema = Depends(AuthPermission(permissions=["system:dict_type:create"]))
) -> JSONResponse:
result_dict = await DictTypeService.create_obj_service(auth=auth, request=request, data=data)
result_dict = await DictTypeService.create_obj_service(auth=auth, redis=redis, data=data)
logger.info(f"{auth.user.name} 创建字典类型成功: {result_dict}")
return SuccessResponse(data=result_dict, msg="创建字典类型成功")
@router.put("/type/update", summary="修改字典类型", description="修改字典类型")
async def update_type_controller(
request: Request,
data: DictTypeUpdateSchema,
redis: Redis = Depends(redis_getter),
auth: AuthSchema = Depends(AuthPermission(permissions=["system:dict_type:update"]))
) -> JSONResponse:
result_dict = await DictTypeService.update_obj_service(auth=auth, request=request, data=data)
result_dict = await DictTypeService.update_obj_service(auth=auth, redis=redis, data=data)
logger.info(f"{auth.user.name} 修改字典类型成功: {result_dict}")
return SuccessResponse(data=result_dict, msg="修改字典类型成功")
@router.delete("/type/delete", summary="删除字典类型", description="删除字典类型")
async def delete_type_controller(
request: Request,
redis: Redis = Depends(redis_getter),
id: int = Query(..., description="字典类型ID"),
auth: AuthSchema = Depends(AuthPermission(permissions=["system:dict_type:delete"]))
) -> JSONResponse:
await DictTypeService.delete_obj_service(auth=auth, request=request, id=id)
await DictTypeService.delete_obj_service(auth=auth, redis=redis, id=id)
logger.info(f"{auth.user.name} 删除字典类型成功: {id}")
return SuccessResponse(msg="删除字典类型成功")
@@ -123,31 +123,31 @@ async def get_data_list_controller(
@router.post("/data/create", summary="创建字典数据", description="创建字典数据")
async def create_data_controller(
request: Request,
data: DictDataCreateSchema,
redis: Redis = Depends(redis_getter),
auth: AuthSchema = Depends(AuthPermission(permissions=["system:dict_data:create"]))
) -> JSONResponse:
result_dict = await DictDataService.create_obj_service(auth=auth, request=request, data=data)
result_dict = await DictDataService.create_obj_service(auth=auth, redis=redis, data=data)
logger.info(f"{auth.user.name} 创建字典数据成功: {result_dict}")
return SuccessResponse(data=result_dict, msg="创建字典数据成功")
@router.put("/data/update", summary="修改字典数据", description="修改字典数据")
async def update_data_controller(
request: Request,
data: DictDataUpdateSchema,
redis: Redis = Depends(redis_getter),
auth: AuthSchema = Depends(AuthPermission(permissions=["system:dict_data:update"]))
) -> JSONResponse:
result_dict = await DictDataService.update_obj_service(auth=auth, request=request, data=data)
result_dict = await DictDataService.update_obj_service(auth=auth, redis=redis, data=data)
logger.info(f"{auth.user.name} 修改字典数据成功: {result_dict}")
return SuccessResponse(data=result_dict, msg="修改字典数据成功")
@router.delete("/data/delete", summary="删除字典数据", description="删除字典数据")
async def delete_data_controller(
request: Request,
redis: Redis = Depends(redis_getter),
id: int = Query(..., description="字典数据ID"),
auth: AuthSchema = Depends(AuthPermission(permissions=["system:dict_data:delete"]))
) -> JSONResponse:
await DictDataService.delete_obj_service(auth=auth, request=request, id=id)
await DictDataService.delete_obj_service(auth=auth, redis=redis, id=id)
logger.info(f"{auth.user.name} 删除字典数据成功: {id}")
return SuccessResponse(msg="删除字典数据成功")
@@ -171,20 +171,20 @@ async def export_data_list_controller(
@router.get('/type/data', summary="获取字典类型", description="获取字典类型", dependencies=[Depends(AuthPermission(permissions=["system:dict_data:query"]))])
async def query_system_dict_type_options_controller(
request: Request
redis: Redis = Depends(redis_getter)
):
result = await DictDataService.get_init_dict_service(redis=request.app.state.redis)
result = await DictDataService.get_init_dict_service(redis=redis)
logger.info(f"获取初始化字典数据成功 {result}")
return SuccessResponse(data=result, msg="获取初始字典数据成功")
@router.get('/data/type/{dict_type}', summary="根据字典类型获取数据", description="根据字典类型获取数据", dependencies=[Depends(AuthPermission(permissions=["system:dict_data:query"]))])
async def query_system_dict_type_data_controller(
request: Request,
dict_type: str
dict_type: str,
redis: Redis = Depends(redis_getter)
):
# 获取全量数据
dict_data_query_result = await DictDataService.query_init_dict_service(
redis=request.app.state.redis, dict_type=dict_type
redis=redis, dict_type=dict_type
)
logger.info(f"获取字典数据:{dict_data_query_result}")
@@ -1,6 +1,5 @@
# -*- coding: utf-8 -*-
from unittest import result
from fastapi import APIRouter, Depends, Query
from fastapi.responses import JSONResponse, StreamingResponse
@@ -42,7 +42,7 @@ async def user_avatar_upload_controller(
file: UploadFile,
request: Request
) -> JSONResponse:
result_str = await UserService.upload_avatar_service(request=request, file=file)
result_str = await UserService.upload_avatar_service(base_url=str(request.base_url), file=file)
logger.info(f"上传头像成功: {result_str}")
return SuccessResponse(data=result_str, msg='上传头像成功')
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
from fastapi import Request
from aioredis import Redis
from app.common.enums import RedisInitKeyConfig
from app.api.v1.schemas.monitor.cache_schema import CacheMonitorSchema, CacheInfoSchema
@@ -12,16 +12,16 @@ class CacheService:
"""
@classmethod
async def get_cache_monitor_statistical_info_service(cls, request: Request)->dict:
async def get_cache_monitor_statistical_info_service(cls, redis: Redis)->dict:
"""
获取缓存监控信息service
:param request: Request对象
:param redis: Redis对象
:return: 缓存监控信息
"""
info = await RedisCURD(request.app.state.redis).info()
db_size = await RedisCURD(request.app.state.redis).db_size()
command_stats_dict = await RedisCURD(request.app.state.redis).commandstats()
info = await RedisCURD(redis).info()
db_size = await RedisCURD(redis).db_size()
command_stats_dict = await RedisCURD(redis).commandstats()
command_stats = [
dict(name=key.split('_')[1], value=str(value.get('calls'))) for key, value in command_stats_dict.items()
@@ -51,73 +51,73 @@ class CacheService:
return name_list
@classmethod
async def get_cache_monitor_cache_key_service(cls, request: Request, cache_name: str)->list:
async def get_cache_monitor_cache_key_service(cls, redis: Redis, cache_name: str)->list:
"""
获取缓存键名列表信息service
:param request: Request对象
:param redis: Redis对象
:param cache_name: 缓存名称
:return: 缓存键名列表信息
"""
cache_keys = await RedisCURD(request.app.state.redis).get_keys(f'{cache_name}*')
cache_keys = await RedisCURD(redis).get_keys(f'{cache_name}*')
cache_key_list = [key.split(':', 1)[1] for key in cache_keys if key.startswith(f'{cache_name}:')]
return cache_key_list
@classmethod
async def get_cache_monitor_cache_value_service(cls, request: Request, cache_name: str, cache_key: str)->dict:
async def get_cache_monitor_cache_value_service(cls, redis: Redis, cache_name: str, cache_key: str)->dict:
"""
获取缓存内容信息service
:param request: Request对象
:param redis: Redis对象
:param cache_name: 缓存名称
:param cache_key: 缓存键名
:return: 缓存内容信息
"""
cache_value = await RedisCURD(request.app.state.redis).get(f'{cache_name}:{cache_key}')
cache_value = await RedisCURD(redis).get(f'{cache_name}:{cache_key}')
return CacheInfoSchema(cache_key=cache_key, cache_name=cache_name, cache_value=cache_value, remark='').model_dump()
@classmethod
async def clear_cache_monitor_cache_name_service(cls, request: Request, cache_name: str)->bool:
async def clear_cache_monitor_cache_name_service(cls, redis: Redis, cache_name: str)->bool:
"""
清除缓存名称对应所有键值service
:param request: Request对象
:param redis: Redis对象
:param cache_name: 缓存名称
:return: 操作缓存响应信息
"""
cache_keys = await RedisCURD(request.app.state.redis).get_keys(f'{cache_name}*')
cache_keys = await RedisCURD(redis).get_keys(f'{cache_name}*')
if cache_keys:
await RedisCURD(request.app.state.redis).delete(*cache_keys)
await RedisCURD(redis).delete(*cache_keys)
return True
@classmethod
async def clear_cache_monitor_cache_key_service(cls, request: Request, cache_key: str)->bool:
async def clear_cache_monitor_cache_key_service(cls, redis: Redis, cache_key: str)->bool:
"""
清除缓存名称对应所有键值service
:param request: Request对象
:param redis: Redis对象
:param cache_key: 缓存键名
:return: 操作缓存响应信息
"""
cache_keys = await RedisCURD(request.app.state.redis).get_keys(f'*{cache_key}')
cache_keys = await RedisCURD(redis).get_keys(f'*{cache_key}')
if cache_keys:
await RedisCURD(request.app.state.redis).delete(*cache_keys)
await RedisCURD(redis).delete(*cache_keys)
return True
@classmethod
async def clear_cache_monitor_all_service(cls, request: Request)->bool:
async def clear_cache_monitor_all_service(cls, redis: Redis)->bool:
"""
清除所有缓存service
:param request: Request对象
:param redis: Redis对象
:return: 操作缓存响应信息
"""
cache_keys = await RedisCURD(request.app.state.redis).get_keys
cache_keys = await RedisCURD(redis).get_keys
if cache_keys:
await RedisCURD(request.app.state.redis).delete(*cache_keys)
await RedisCURD(redis).delete(*cache_keys)
return True
@@ -2,7 +2,7 @@
import json
from typing import Dict, List
from fastapi import Request
from aioredis import Redis
from app.common.enums import RedisInitKeyConfig
from app.core.exceptions import CustomException
@@ -14,15 +14,15 @@ class OnlineService:
"""在线用户管理模块服务层"""
@classmethod
async def get_online_list_service(cls, request: Request, search: OnlineQueryParams) -> List[Dict]:
async def get_online_list_service(cls, redis: Redis, search: OnlineQueryParams) -> List[Dict]:
"""获取在线用户列表信息"""
# 获取所有在线用户信息
token_keys = await RedisCURD(request.app.state.redis).get_keys(f'{RedisInitKeyConfig.ONLINE_USER.key}*')
token_keys = await RedisCURD(redis).get_keys(f'{RedisInitKeyConfig.ONLINE_USER.key}*')
if not token_keys:
return []
# 批量获取在线用户信息
online_values = await RedisCURD(request.app.state.redis).mget(*token_keys)
online_values = await RedisCURD(redis).mget(*token_keys)
online_list = []
for online_value in online_values:
@@ -46,16 +46,16 @@ class OnlineService:
return online_list
@classmethod
async def delete_online_service(cls, request: Request, username: str) -> bool:
async def delete_online_service(cls, redis: Redis, username: str) -> bool:
"""强制下线在线用户"""
if not username:
raise CustomException(msg='传入username不能为空')
# 批量删除token
await RedisCURD(request.app.state.redis).delete(f"{RedisInitKeyConfig.ONLINE_USER.key}:{username}")
await RedisCURD(request.app.state.redis).delete(f"{RedisInitKeyConfig.ACCESS_TOKEN.key}:{username}")
await RedisCURD(request.app.state.redis).delete(f"{RedisInitKeyConfig.REFRESH_TOKEN.key}:{username}")
await RedisCURD(redis).delete(f"{RedisInitKeyConfig.ONLINE_USER.key}:{username}")
await RedisCURD(redis).delete(f"{RedisInitKeyConfig.ACCESS_TOKEN.key}:{username}")
await RedisCURD(redis).delete(f"{RedisInitKeyConfig.REFRESH_TOKEN.key}:{username}")
return True
@staticmethod
@@ -2,6 +2,7 @@
from typing import Dict, Union, NewType
from fastapi import Request
from aioredis import Redis
from sqlalchemy.ext.asyncio import AsyncSession
from datetime import datetime, timedelta
from user_agents import parse
@@ -40,7 +41,7 @@ class LoginService:
"""登录认证服务"""
@classmethod
async def authenticate_user_service(cls, request: Request, login_form: CustomOAuth2PasswordRequestForm, db: AsyncSession) -> UserModel:
async def authenticate_user_service(cls, request: Request, redis: Redis, login_form: CustomOAuth2PasswordRequestForm, db: AsyncSession) -> UserModel:
"""
用户认证
@@ -61,7 +62,7 @@ class LoginService:
# 验证码校验
if settings.CAPTCHA_ENABLE and not request_from_docs:
await CaptchaService.check_captcha_service(request=request, key=login_form.captcha_key, captcha=login_form.captcha)
await CaptchaService.check_captcha_service(redis=redis, key=login_form.captcha_key, captcha=login_form.captcha)
# 用户认证
auth = AuthSchema(db=db)
@@ -81,11 +82,11 @@ class LoginService:
user = await UserCRUD(auth).update_last_login_crud(id=user.id)
# 创建token
token = await cls.create_token_service(request=request, username=user.username)
token = await cls.create_token_service(redis=redis, username=user.username)
user_agent = parse(request.headers.get("user-agent"))
# 缓存中构建在线用户信息
await RedisCURD(request.app.state.redis).set(
await RedisCURD(redis).set(
key=f"{RedisInitKeyConfig.ONLINE_USER.key}:{user.username}",
value=OnlineOutSchema(
session_id=token.access_token,
@@ -104,7 +105,7 @@ class LoginService:
return user
@classmethod
async def create_token_service(cls, request: Request, username: str) -> JWTOutSchema:
async def create_token_service(cls, redis: Redis, username: str) -> JWTOutSchema:
"""
创建访问令牌和刷新令牌
@@ -131,17 +132,17 @@ class LoginService:
))
# 清除该用户之前的token
await RedisCURD(request.app.state.redis).delete(f'{RedisInitKeyConfig.ACCESS_TOKEN.key}:{username}')
await RedisCURD(request.app.state.redis).delete(f'{RedisInitKeyConfig.REFRESH_TOKEN.key}:{username}')
await RedisCURD(redis).delete(f'{RedisInitKeyConfig.ACCESS_TOKEN.key}:{username}')
await RedisCURD(redis).delete(f'{RedisInitKeyConfig.REFRESH_TOKEN.key}:{username}')
# 设置新的token
await RedisCURD(request.app.state.redis).set(
await RedisCURD(redis).set(
key=f'{RedisInitKeyConfig.ACCESS_TOKEN.key}:{username}',
value=access_token,
expire=int(access_expires.total_seconds())
)
await RedisCURD(request.app.state.redis).set(
await RedisCURD(redis).set(
key=f'{RedisInitKeyConfig.REFRESH_TOKEN.key}:{username}',
value=refresh_token,
expire=int(refresh_expires.total_seconds())
@@ -155,7 +156,7 @@ class LoginService:
)
@classmethod
async def refresh_token_service(cls, request: Request, refresh_token: RefreshTokenPayloadSchema) -> JWTOutSchema:
async def refresh_token_service(cls, redis: Redis, refresh_token: RefreshTokenPayloadSchema) -> JWTOutSchema:
"""
刷新访问令牌
@@ -172,10 +173,10 @@ class LoginService:
if not token_payload.is_refresh:
raise CustomException(msg="非法凭证")
return await cls.create_token_service(request=request, username=token_payload.sub)
return await cls.create_token_service(redis=redis, username=token_payload.sub)
@classmethod
async def logout_services_service(cls, request: Request, token: LogoutPayloadSchema) -> bool:
async def logout_services_service(cls, redis: Redis, token: LogoutPayloadSchema) -> bool:
"""
退出登录
@@ -190,9 +191,9 @@ class LoginService:
username: str = payload.sub
# 删除Redis中的在线用户、访问令牌、刷新令牌
await RedisCURD(request.app.state.redis).delete(f"{RedisInitKeyConfig.ONLINE_USER.key}:{username}")
await RedisCURD(request.app.state.redis).delete(f"{RedisInitKeyConfig.ACCESS_TOKEN.key}:{username}")
await RedisCURD(request.app.state.redis).delete(f"{RedisInitKeyConfig.REFRESH_TOKEN.key}:{username}")
await RedisCURD(redis).delete(f"{RedisInitKeyConfig.ONLINE_USER.key}:{username}")
await RedisCURD(redis).delete(f"{RedisInitKeyConfig.ACCESS_TOKEN.key}:{username}")
await RedisCURD(redis).delete(f"{RedisInitKeyConfig.REFRESH_TOKEN.key}:{username}")
logger.info(f"用户退出登录成功,会话账号:{username}")
return True
@@ -202,7 +203,7 @@ class CaptchaService:
"""验证码服务"""
@classmethod
async def get_captcha_service(cls, request: Request) -> Dict[str, Union[CaptchaKey, CaptchaBase64]]:
async def get_captcha_service(cls, redis: Redis) -> Dict[str, Union[CaptchaKey, CaptchaBase64]]:
"""
获取验证码
@@ -224,7 +225,7 @@ class CaptchaService:
# 保存到Redis并设置过期时间
redis_key = f"{RedisInitKeyConfig.CAPTCHA_CODES.key}:{captcha_key}"
await RedisCURD(request.app.state.redis).set(
await RedisCURD(redis).set(
key=redis_key,
value=captcha_value,
expire=settings.CAPTCHA_EXPIRE_SECONDS
@@ -239,7 +240,7 @@ class CaptchaService:
).model_dump()
@classmethod
async def check_captcha_service(cls, request: Request, key: str, captcha: str) -> bool:
async def check_captcha_service(cls, redis: Redis, key: str, captcha: str) -> bool:
"""
校验验证码
@@ -260,7 +261,7 @@ class CaptchaService:
# 获取Redis中存储的验证码
redis_key = f'{RedisInitKeyConfig.CAPTCHA_CODES.key}:{key}'
captcha_value = await RedisCURD(request.app.state.redis).get(redis_key)
captcha_value = await RedisCURD(redis).get(redis_key)
if not captcha_value:
logger.warning('验证码已过期或不存在')
raise CustomException(msg="验证码已过期")
@@ -271,6 +272,6 @@ class CaptchaService:
raise CustomException(msg="验证码错误")
# 验证成功后删除验证码,避免重复使用
await RedisCURD(request.app.state.redis).delete(redis_key)
await RedisCURD(redis).delete(redis_key)
logger.info(f'验证码校验成功,key:{key}')
return True
@@ -3,7 +3,8 @@
import json
from typing import Dict
from fastapi import Request, UploadFile
from aioredis import Redis
from fastapi import UploadFile
from sqlalchemy.ext.asyncio import AsyncSession
from aioredis import Redis
@@ -30,7 +31,7 @@ class ConfigService:
return ConfigOutSchema.model_validate(config_obj).model_dump()
@classmethod
async def update_service(cls, auth: AuthSchema, request: Request, data: ConfigUpdateSchema) -> Dict:
async def update_service(cls, auth: AuthSchema, redis: Redis, data: ConfigUpdateSchema) -> bool:
new_obj = await ConfigCRUD(auth).update_crud(id=data.id, data=data)
new_obj_dict = ConfigOutSchema.model_validate(new_obj).model_dump()
@@ -38,19 +39,20 @@ class ConfigService:
redis_key = f"{RedisInitKeyConfig.System_Config.key}:{'init_system_config'}"
try:
value = json.dumps(new_obj_dict, ensure_ascii=False)
await RedisCURD(request.app.state.redis).set(
await RedisCURD(redis).set(
key=redis_key,
value=value,
expire=settings.ACCESS_TOKEN_EXPIRE_MINUTES * 60
)
logger.info(f"更新系统配置成功: {new_obj_dict}")
return True
except Exception as e:
logger.error(f"更新系统配置失败: {e}")
raise CustomException(msg="更新系统配置失败")
return new_obj_dict
@classmethod
async def upload_service(cls, request: Request, file: UploadFile) -> Dict:
async def upload_service(cls, base_url: str, file: UploadFile) -> Dict:
"""上传文件"""
if not file:
raise CustomException(msg="请选择要上传的文件")
@@ -60,11 +62,11 @@ class ConfigService:
file_path=f'{filepath}',
file_name=filename,
origin_name=file.filename,
file_url=f'{request.base_url}{filepath}',
file_url=f'{base_url}{filepath}',
).model_dump()
@classmethod
async def init_config_service(cls, redis: Redis, db: AsyncSession):
async def init_config_service(cls, redis: Redis, db: AsyncSession)-> None:
auth = AuthSchema(db=db)
config_obj = await ConfigCRUD(auth).get_crud(id=1)
config_obj_dict = ConfigOutSchema.model_validate(config_obj).model_dump()
@@ -83,10 +85,10 @@ class ConfigService:
raise CustomException(msg="初始化系统配置失败")
@classmethod
async def get_init_config_service(cls, request: Request) -> Dict:
async def get_init_config_service(cls, redis: Redis) -> Dict:
"""获取系统配置"""
redis_key = f"{RedisInitKeyConfig.System_Config.key}:{'init_system_config'}"
config_obj_list_dict = await RedisCURD(request.app.state.redis).get(redis_key)
config_obj_list_dict = await RedisCURD(redis).get(redis_key)
if not config_obj_list_dict:
raise CustomException(msg="系统配置不存在")
return json.loads(config_obj_list_dict)
@@ -3,7 +3,6 @@
import json
from typing import Any, List, Dict
from aioredis import Redis
from fastapi import Request
from sqlalchemy.ext.asyncio import AsyncSession
from app.api.v1.schemas.system.auth_schema import AuthSchema
@@ -35,7 +34,7 @@ class DictTypeService:
return [DictTypeOutSchema.model_validate(obj).model_dump() for obj in obj_list]
@classmethod
async def create_obj_service(cls, auth: AuthSchema,request: Request, data: DictTypeCreateSchema) -> Dict:
async def create_obj_service(cls, auth: AuthSchema, redis: Redis, data: DictTypeCreateSchema) -> Dict:
exist_obj = await DictTypeCRUD(auth).get(dict_name=data.dict_name)
if exist_obj:
raise CustomException(msg='创建失败,该数据字典类型已存在')
@@ -46,7 +45,7 @@ class DictTypeService:
redis_key = f"{RedisInitKeyConfig.System_Dict.key}:{data.dict_type}"
try:
await RedisCURD(request.app.state.redis).set(
await RedisCURD(redis).set(
key=redis_key,
value="",
expire=settings.ACCESS_TOKEN_EXPIRE_MINUTES * 60
@@ -59,7 +58,7 @@ class DictTypeService:
return new_obj_dict
@classmethod
async def update_obj_service(cls, auth: AuthSchema, request: Request, data: DictTypeUpdateSchema) -> Dict:
async def update_obj_service(cls, auth: AuthSchema, redis: Redis, data: DictTypeUpdateSchema) -> Dict:
exist_obj = await DictTypeCRUD(auth).get_obj_by_id_crud(id=data.id)
if not exist_obj:
raise CustomException(msg='更新失败,该数据字典类型不存在')
@@ -101,7 +100,7 @@ class DictTypeService:
dict_data = [DictDataOutSchema.model_validate(row).model_dump() for row in dict_data_list if row]
value = json.dumps(dict_data, ensure_ascii=False)
await RedisCURD(request.app.state.redis).set(
await RedisCURD(redis).set(
key=redis_key,
value=value,
expire=settings.ACCESS_TOKEN_EXPIRE_MINUTES * 60
@@ -114,7 +113,7 @@ class DictTypeService:
return new_obj_dict
@classmethod
async def delete_obj_service(cls, auth: AuthSchema, request: Request, id: int) -> None:
async def delete_obj_service(cls, auth: AuthSchema, redis: Redis, id: int) -> None:
exist_obj = await DictTypeCRUD(auth).get_obj_by_id_crud(id=id)
if not exist_obj:
raise CustomException(msg='删除失败,该数据字典类型不存在')
@@ -127,7 +126,7 @@ class DictTypeService:
# 删除Redis缓存
redis_key = f"{RedisInitKeyConfig.System_Dict.key}:{exist_obj.dict_type}"
try:
await RedisCURD(request.app.state.redis).delete(redis_key)
await RedisCURD(redis).delete(redis_key)
logger.info(f"删除字典类型成功: {id}")
except Exception as e:
logger.error(f"删除字典类型失败: {e}")
@@ -225,7 +224,7 @@ class DictDataService:
return obj_list_dict
@classmethod
async def create_obj_service(cls, auth: AuthSchema, request: Request, data: DictDataCreateSchema) -> Dict:
async def create_obj_service(cls, auth: AuthSchema, redis: Redis, data: DictDataCreateSchema) -> Dict:
exist_obj = await DictDataCRUD(auth).get(dict_label=data.dict_label)
if exist_obj:
raise CustomException(msg='创建失败,该字典数据已存在')
@@ -238,7 +237,7 @@ class DictDataService:
dict_data = [DictDataOutSchema.model_validate(row).model_dump() for row in dict_data_list if row]
value = json.dumps(dict_data, ensure_ascii=False)
await RedisCURD(request.app.state.redis).set(
await RedisCURD(redis).set(
key=redis_key,
value=value,
expire=settings.ACCESS_TOKEN_EXPIRE_MINUTES * 60
@@ -251,7 +250,7 @@ class DictDataService:
return DictDataOutSchema.model_validate(obj).model_dump()
@classmethod
async def update_obj_service(cls, auth: AuthSchema, request: Request, data: DictDataUpdateSchema) -> Dict:
async def update_obj_service(cls, auth: AuthSchema, redis: Redis, data: DictDataUpdateSchema) -> Dict:
exist_obj = await DictDataCRUD(auth).get_obj_by_id_crud(id=data.id)
if not exist_obj:
raise CustomException(msg='更新失败,该字典数据不存在')
@@ -277,7 +276,7 @@ class DictDataService:
dict_data_list = await DictDataCRUD(auth).get_obj_list_crud(search={'dict_type': dict_type.dict_type})
dict_data = [DictDataOutSchema.model_validate(row).model_dump() for row in dict_data_list if row]
value = json.dumps(dict_data, ensure_ascii=False)
await RedisCURD(request.app.state.redis).set(
await RedisCURD(redis).set(
key=redis_key,
value=value,
expire=settings.ACCESS_TOKEN_EXPIRE_MINUTES * 60
@@ -293,7 +292,7 @@ class DictDataService:
dict_data = [DictDataOutSchema.model_validate(row).model_dump() for row in dict_data_list if row]
value = json.dumps(dict_data, ensure_ascii=False)
await RedisCURD(request.app.state.redis).set(
await RedisCURD(redis).set(
key=redis_key,
value=value,
expire=settings.ACCESS_TOKEN_EXPIRE_MINUTES * 60
@@ -306,7 +305,7 @@ class DictDataService:
return DictDataOutSchema.model_validate(obj).model_dump()
@classmethod
async def delete_obj_service(cls, auth: AuthSchema, request: Request, id: int) -> None:
async def delete_obj_service(cls, auth: AuthSchema, redis: Redis, id: int) -> None:
exist_obj = await DictDataCRUD(auth).get_obj_by_id_crud(id=id)
if not exist_obj:
raise CustomException(msg='删除失败,该字典数据不存在')
@@ -315,7 +314,7 @@ class DictDataService:
redis_key = f"{RedisInitKeyConfig.System_Dict.key}:{exist_obj.dict_type}"
try:
# 删除Redis缓存
await RedisCURD(request.app.state.redis).delete(redis_key)
await RedisCURD(redis).delete(redis_key)
logger.info(f"删除字典数据成功: {id}")
except Exception as e:
logger.error(f"删除字典数据失败: {e}")
@@ -2,7 +2,7 @@
import io
from typing import Any, Dict, List
from fastapi import Request, UploadFile
from fastapi import UploadFile
import pandas as pd
from app.core.exceptions import CustomException
@@ -207,7 +207,7 @@ class UserService:
await UserCRUD(auth).set_available_crud(ids=data.ids, available=data.available)
@classmethod
async def upload_avatar_service(cls, request: Request, file: UploadFile) -> Dict:
async def upload_avatar_service(cls, base_url: str, file: UploadFile) -> Dict:
"""上传头像"""
if not file:
raise CustomException(msg="请选择要上传的文件")
@@ -217,7 +217,7 @@ class UserService:
file_path=f'{filepath}',
file_name=filename,
origin_name=file.filename,
file_url=f'{request.base_url}{filepath}',
file_url=f'{base_url}{filepath}',
).model_dump()
@classmethod