Skip to content

Commit 7c9ab70

Browse files
committed
feat:新增系统参数设置模块,用于初始化系统设置(如是否开启登录验证码)
fix:修复SwaggerUI文档成功验证OAuth2后请求接口时token依然为undefined的bug
1 parent dee58f4 commit 7c9ab70

File tree

20 files changed

+1648
-59
lines changed

20 files changed

+1648
-59
lines changed

dash-fastapi-backend/app.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from module_admin.controller.role_controller import roleController
1313
from module_admin.controller.post_controler import postController
1414
from module_admin.controller.dict_controller import dictController
15+
from module_admin.controller.config_controller import configController
1516
from module_admin.controller.notice_controller import noticeController
1617
from module_admin.controller.log_controller import logController
1718
from module_admin.controller.online_controller import onlineController
@@ -55,6 +56,7 @@ async def startup_event():
5556
await init_create_table()
5657
app.state.redis = await RedisUtil.create_redis_pool()
5758
await RedisUtil.init_sys_dict(app.state.redis)
59+
await RedisUtil.init_sys_config(app.state.redis)
5860
await SchedulerUtil.init_system_scheduler()
5961
logger.info("Dash-FastAPI启动成功")
6062

@@ -87,6 +89,7 @@ async def http_exception_handler(request: Request, exc: HTTPException):
8789
app.include_router(roleController, prefix="/system", tags=['系统管理-角色管理'])
8890
app.include_router(postController, prefix="/system", tags=['系统管理-岗位管理'])
8991
app.include_router(dictController, prefix="/system", tags=['系统管理-字典管理'])
92+
app.include_router(configController, prefix="/system", tags=['系统管理-参数管理'])
9093
app.include_router(noticeController, prefix="/system", tags=['系统管理-通知公告管理'])
9194
app.include_router(logController, prefix="/system", tags=['系统管理-日志管理'])
9295
app.include_router(onlineController, prefix="/monitor", tags=['系统监控-在线用户'])

dash-fastapi-backend/config/get_redis.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import aioredis
22
from module_admin.service.dict_service import DictDataService
3+
from module_admin.service.config_service import ConfigService
34
from config.env import RedisConfig
45
from config.database import SessionLocal
56
from utils.log_util import logger
@@ -50,3 +51,15 @@ async def init_sys_dict(cls, redis):
5051
await DictDataService.init_cache_sys_dict_services(session, redis)
5152

5253
session.close()
54+
55+
@classmethod
56+
async def init_sys_config(cls, redis):
57+
"""
58+
应用启动时缓存参数配置表
59+
:param redis: redis对象
60+
:return:
61+
"""
62+
session = SessionLocal()
63+
await ConfigService.init_cache_sys_config_services(session, redis)
64+
65+
session.close()

dash-fastapi-backend/module_admin/annotation/log_annotation.py

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ async def wrapper(*args, **kwargs):
4545
operator_type = 1
4646
if "Mobile" in user_agent or "Android" in user_agent or "iPhone" in user_agent:
4747
operator_type = 2
48+
# 获取请求的url
4849
oper_url = request.url.path
50+
# 获取请求的ip及ip归属区域
4951
oper_ip = request.headers.get('remote_addr')
5052
oper_location = '内网IP'
5153
try:
@@ -64,17 +66,21 @@ async def wrapper(*args, **kwargs):
6466
oper_location = '未知'
6567
print(e)
6668
finally:
69+
# 根据不同的请求类型使用不同的方法获取请求参数
6770
content_type = request.headers.get("Content-Type")
6871
if content_type and ("multipart/form-data" in content_type or 'application/x-www-form-urlencoded' in content_type):
6972
payload = await request.form()
7073
oper_param = "\n".join([f"{key}: {value}" for key, value in payload.items()])
7174
else:
7275
payload = await request.body()
7376
oper_param = json.dumps(json.loads(str(payload, 'utf-8')), ensure_ascii=False)
77+
# 日志表请求参数字段长度最大为2000,因此在此处判断长度
7478
if len(oper_param) > 2000:
7579
oper_param = '请求参数过长'
7680

81+
# 获取操作时间
7782
oper_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
83+
# 此处在登录之前向原始函数传递一些登录信息,用于监测在线用户的相关信息
7884
login_log = {}
7985
if log_type == 'login':
8086
user_agent_info = parse(user_agent)
@@ -90,29 +96,43 @@ async def wrapper(*args, **kwargs):
9096
kwargs['form_data'].login_info = login_log
9197
# 调用原始函数
9298
result = await func(*args, **kwargs)
99+
# 获取请求耗时
93100
cost_time = float(time.time() - start_time) * 100
101+
# 判断请求是否来自api文档
102+
request_from_swagger = request.headers.get('referer').endswith('docs') if request.headers.get('referer') else False
103+
request_from_redoc = request.headers.get('referer').endswith('redoc') if request.headers.get('referer') else False
104+
# 根据响应结果的类型使用不同的方法获取响应结果参数
94105
if isinstance(result, JSONResponse) or isinstance(result, ORJSONResponse) or isinstance(result, UJSONResponse):
95106
result_dict = json.loads(str(result.body, 'utf-8'))
96107
else:
97-
if result.status_code == 200:
98-
result_dict = {'code': result.status_code, 'message': '获取成功'}
108+
if request_from_swagger or request_from_redoc:
109+
result_dict = {}
99110
else:
100-
result_dict = {'code': result.status_code, 'message': '获取失败'}
111+
if result.status_code == 200:
112+
result_dict = {'code': result.status_code, 'message': '获取成功'}
113+
else:
114+
result_dict = {'code': result.status_code, 'message': '获取失败'}
101115
json_result = json.dumps(dict(code=result_dict.get('code'), message=result_dict.get('message')), ensure_ascii=False)
116+
# 根据响应结果获取响应状态及异常信息
102117
status = 1
103118
error_msg = ''
104119
if result_dict.get('code') == 200:
105120
status = 0
106121
else:
107122
error_msg = result_dict.get('message')
123+
# 根据日志类型向对应的日志表插入数据
108124
if log_type == 'login':
109-
user = kwargs.get('form_data')
110-
user_name = user.username
111-
login_log['user_name'] = user_name
112-
login_log['status'] = str(status)
113-
login_log['msg'] = result_dict.get('message')
125+
# 登录请求来自于api文档时不记录登录日志,其余情况则记录
126+
if request_from_swagger or request_from_redoc:
127+
pass
128+
else:
129+
user = kwargs.get('form_data')
130+
user_name = user.username
131+
login_log['user_name'] = user_name
132+
login_log['status'] = str(status)
133+
login_log['msg'] = result_dict.get('message')
114134

115-
LoginLogService.add_login_log_services(query_db, LogininforModel(**login_log))
135+
LoginLogService.add_login_log_services(query_db, LogininforModel(**login_log))
116136
else:
117137
current_user = await get_current_user(request, token, query_db)
118138
oper_name = current_user.user.user_name

dash-fastapi-backend/module_admin/controller/common_controller.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from config.env import CachePathConfig
44
from module_admin.service.login_service import get_current_user
55
from module_admin.service.common_service import *
6+
from module_admin.service.config_service import ConfigService
67
from utils.response_util import *
78
from utils.log_util import *
89
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
@@ -70,3 +71,15 @@ def generate_file():
7071
except Exception as e:
7172
logger.exception(e)
7273
return response_500(data="", message=str(e))
74+
75+
76+
@commonController.get("/config/query/{config_key}")
77+
async def query_system_config(request: Request, config_key: str):
78+
try:
79+
# 获取全量数据
80+
config_query_result = await ConfigService.query_config_list_from_cache_services(request.app.state.redis, config_key)
81+
logger.info('获取成功')
82+
return response_200(data=config_query_result, message="获取成功")
83+
except Exception as e:
84+
logger.exception(e)
85+
return response_500(data="", message=str(e))
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
from fastapi import APIRouter, Request
2+
from fastapi import Depends
3+
from config.get_db import get_db
4+
from module_admin.service.login_service import get_current_user, CurrentUserInfoServiceResponse
5+
from module_admin.service.config_service import *
6+
from module_admin.entity.vo.config_vo import *
7+
from utils.response_util import *
8+
from utils.log_util import *
9+
from utils.page_util import get_page_obj
10+
from utils.common_util import bytes2file_response
11+
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
12+
from module_admin.annotation.log_annotation import log_decorator
13+
14+
15+
configController = APIRouter(dependencies=[Depends(get_current_user)])
16+
17+
18+
@configController.post("/config/get", response_model=ConfigPageObjectResponse, dependencies=[Depends(CheckUserInterfaceAuth('system:config:list'))])
19+
async def get_system_config_list(request: Request, config_page_query: ConfigPageObject, query_db: Session = Depends(get_db)):
20+
try:
21+
config_query = ConfigQueryModel(**config_page_query.dict())
22+
# 获取全量数据
23+
config_query_result = ConfigService.get_config_list_services(query_db, config_query)
24+
# 分页操作
25+
config_page_query_result = get_page_obj(config_query_result, config_page_query.page_num, config_page_query.page_size)
26+
logger.info('获取成功')
27+
return response_200(data=config_page_query_result, message="获取成功")
28+
except Exception as e:
29+
logger.exception(e)
30+
return response_500(data="", message=str(e))
31+
32+
33+
@configController.post("/config/add", response_model=CrudConfigResponse, dependencies=[Depends(CheckUserInterfaceAuth('system:config:add'))])
34+
@log_decorator(title='参数管理', business_type=1)
35+
async def add_system_config(request: Request, add_config: ConfigModel, query_db: Session = Depends(get_db), current_user: CurrentUserInfoServiceResponse = Depends(get_current_user)):
36+
try:
37+
add_config.create_by = current_user.user.user_name
38+
add_config.update_by = current_user.user.user_name
39+
add_config_result = await ConfigService.add_config_services(request, query_db, add_config)
40+
if add_config_result.is_success:
41+
logger.info(add_config_result.message)
42+
return response_200(data=add_config_result, message=add_config_result.message)
43+
else:
44+
logger.warning(add_config_result.message)
45+
return response_400(data="", message=add_config_result.message)
46+
except Exception as e:
47+
logger.exception(e)
48+
return response_500(data="", message=str(e))
49+
50+
51+
@configController.patch("/config/edit", response_model=CrudConfigResponse, dependencies=[Depends(CheckUserInterfaceAuth('system:config:edit'))])
52+
@log_decorator(title='参数管理', business_type=2)
53+
async def edit_system_config(request: Request, edit_config: ConfigModel, query_db: Session = Depends(get_db), current_user: CurrentUserInfoServiceResponse = Depends(get_current_user)):
54+
try:
55+
edit_config.update_by = current_user.user.user_name
56+
edit_config.update_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
57+
edit_config_result = await ConfigService.edit_config_services(request, query_db, edit_config)
58+
if edit_config_result.is_success:
59+
logger.info(edit_config_result.message)
60+
return response_200(data=edit_config_result, message=edit_config_result.message)
61+
else:
62+
logger.warning(edit_config_result.message)
63+
return response_400(data="", message=edit_config_result.message)
64+
except Exception as e:
65+
logger.exception(e)
66+
return response_500(data="", message=str(e))
67+
68+
69+
@configController.post("/config/delete", response_model=CrudConfigResponse, dependencies=[Depends(CheckUserInterfaceAuth('system:config:remove'))])
70+
@log_decorator(title='参数管理', business_type=3)
71+
async def delete_system_config(request: Request, delete_config: DeleteConfigModel, query_db: Session = Depends(get_db)):
72+
try:
73+
delete_config_result = await ConfigService.delete_config_services(request, query_db, delete_config)
74+
if delete_config_result.is_success:
75+
logger.info(delete_config_result.message)
76+
return response_200(data=delete_config_result, message=delete_config_result.message)
77+
else:
78+
logger.warning(delete_config_result.message)
79+
return response_400(data="", message=delete_config_result.message)
80+
except Exception as e:
81+
logger.exception(e)
82+
return response_500(data="", message=str(e))
83+
84+
85+
@configController.get("/config/{config_id}", response_model=ConfigModel, dependencies=[Depends(CheckUserInterfaceAuth('system:config:query'))])
86+
async def query_detail_system_config(request: Request, config_id: int, query_db: Session = Depends(get_db)):
87+
try:
88+
detail_config_result = ConfigService.detail_config_services(query_db, config_id)
89+
logger.info(f'获取config_id为{config_id}的信息成功')
90+
return response_200(data=detail_config_result, message='获取成功')
91+
except Exception as e:
92+
logger.exception(e)
93+
return response_500(data="", message=str(e))
94+
95+
96+
@configController.post("/config/export", dependencies=[Depends(CheckUserInterfaceAuth('system:config:export'))])
97+
@log_decorator(title='参数管理', business_type=5)
98+
async def export_system_config_list(request: Request, config_query: ConfigQueryModel, query_db: Session = Depends(get_db)):
99+
try:
100+
# 获取全量数据
101+
config_query_result = ConfigService.get_config_list_services(query_db, config_query)
102+
config_export_result = ConfigService.export_config_list_services(config_query_result)
103+
logger.info('导出成功')
104+
return streaming_response_200(data=bytes2file_response(config_export_result))
105+
except Exception as e:
106+
logger.exception(e)
107+
return response_500(data="", message=str(e))
108+
109+
110+
@configController.post("/config/refresh", response_model=CrudConfigResponse, dependencies=[Depends(CheckUserInterfaceAuth('system:config:edit'))])
111+
@log_decorator(title='参数管理', business_type=2)
112+
async def refresh_system_config(request: Request, query_db: Session = Depends(get_db)):
113+
try:
114+
refresh_config_result = await ConfigService.refresh_sys_config_services(request, query_db)
115+
if refresh_config_result.is_success:
116+
logger.info(refresh_config_result.message)
117+
return response_200(data=refresh_config_result, message=refresh_config_result.message)
118+
else:
119+
logger.warning(refresh_config_result.message)
120+
return response_400(data="", message=refresh_config_result.message)
121+
except Exception as e:
122+
logger.exception(e)
123+
return response_500(data="", message=str(e))

dash-fastapi-backend/module_admin/controller/login_controller.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@
1717
@loginController.post("/loginByAccount", response_model=Token)
1818
@log_decorator(title='用户登录', business_type=0, log_type='login')
1919
async def login(request: Request, form_data: CustomOAuth2PasswordRequestForm = Depends(), query_db: Session = Depends(get_db)):
20+
captcha_enabled = True if await request.app.state.redis.get(f'sys_config:sys.account.captchaEnabled') == 'true' else False
2021
user = UserLogin(
2122
**dict(
2223
user_name=form_data.username,
2324
password=form_data.password,
2425
captcha=form_data.captcha,
2526
session_id=form_data.session_id,
26-
login_info=form_data.login_info
27+
login_info=form_data.login_info,
28+
captcha_enabled=captcha_enabled
2729
)
2830
)
2931
try:
@@ -49,8 +51,13 @@ async def login(request: Request, form_data: CustomOAuth2PasswordRequestForm = D
4951
# await request.app.state.redis.set(f'{result.user_id}_access_token', access_token, ex=timedelta(minutes=30))
5052
# await request.app.state.redis.set(f'{result.user_id}_session_id', session_id, ex=timedelta(minutes=30))
5153
logger.info('登录成功')
54+
# 判断请求是否来自于api文档,如果是返回指定格式的结果,用于修复api文档认证成功后token显示undefined的bug
55+
request_from_swagger = request.headers.get('referer').endswith('docs') if request.headers.get('referer') else False
56+
request_from_redoc = request.headers.get('referer').endswith('redoc') if request.headers.get('referer') else False
57+
if request_from_swagger or request_from_redoc:
58+
return {'access_token': access_token, 'token_type': 'Bearer'}
5259
return response_200(
53-
data={'access_token': access_token, 'token_type': 'bearer'},
60+
data={'access_token': access_token, 'token_type': 'Bearer'},
5461
message='登录成功'
5562
)
5663
except Exception as e:

0 commit comments

Comments
 (0)