diff --git a/README.md b/README.md index 5aa73da5c5be8540bcc77735896add0dd5d23107..454237812c71da953970f48393fc2142f6dee3e7 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@
-
+
@@ -97,7 +97,7 @@ Dash-FastAPI-Admin是一套全部开源的快速开发平台,毫无保留给
- *密码:admin123*
- 演示地址:dfadmin管理系统
-## 项目运行相关
+## 项目开发及发布
```bash
# 克隆项目
@@ -110,30 +110,94 @@ cd dash-fastapi-admin
pip3 install -r requirements.txt
```
-### 前端
+### 开发
+
+#### 前端
+```bash
+# 进入前端目录
+cd dash-fastapi-frontend
+
+# 配置应用信息
+在.env.dev文件中配置应用开发模式的相关信息
+
+# 运行前端
+python3 app.py --env=dev
+```
+
+#### 后端
+```bash
+# 进入后端目录
+cd dash-fastapi-backend
+
+# 配置环境
+1.在.env.dev文件中配置开发模式的数据库环境
+2.在.env.dev文件中配置开发模式的redis环境
+
+# 运行sql文件
+1.新建数据库dash-fastapi(默认,可修改)
+2.使用命令或数据库连接工具运行sql文件夹下的dash-fastapi.sql
+
+# 运行后端
+python3 app.py --env=dev
+```
+
+### 发布
+
+本应用发布建议使用nginx部署,nginx代理配置参考如下:
+
+```bash
+server {
+ location / {
+ proxy_set_header Host $http_host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header REMOTE-HOST $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_pass http://127.0.0.1:8088/;
+ }
+
+ location /prod-api {
+ proxy_set_header Host $http_host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header REMOTE-HOST $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_pass http://127.0.0.1:9099/;
+ rewrite ^/prod-api/(.*)$ /$1 break;
+ }
+
+ error_page 500 502 503 504 /50x.html;
+ location = /50x.html {
+ root html;
+ }
+}
+```
+
+#### 前端
```bash
# 进入前端目录
cd dash-fastapi-frontend
+# 配置应用信息
+在.env.prod文件中配置应用发布的相关信息,注意:APP_BASE_URL需要配置为nginx代理的地址,例如上面的nginx代理监听的是8000端口,则APP_BASE_URL需要配置为http://127.0.0.1:8000
+
# 运行前端
-python3 wsgi.py
+python3 wsgi.py --env=prod
```
-### 后端
+#### 后端
```bash
# 进入后端目录
cd dash-fastapi-backend
# 配置环境
-1.在config/env.py的DataBaseConfig类中配置数据库环境
-2.在config/env.py的RedisConfig类中配置redis环境
+1.在.env.prod文件中配置生产模式的数据库环境
+2.在.env.prod文件中配置生产模式的redis环境
# 运行sql文件
1.新建数据库dash-fastapi(默认,可修改)
2.使用命令或数据库连接工具运行sql文件夹下的dash-fastapi.sql
# 运行后端
-python3 app.py
+python3 app.py --env=prod
```
### 访问
diff --git a/dash-fastapi-backend/.env.dev b/dash-fastapi-backend/.env.dev
new file mode 100644
index 0000000000000000000000000000000000000000..168937607546c174cc5ba9105fbfefb98dc89046
--- /dev/null
+++ b/dash-fastapi-backend/.env.dev
@@ -0,0 +1,50 @@
+# -------- 应用配置 --------
+# 应用运行环境
+APP_ENV = 'dev'
+# 应用名称
+APP_NAME = 'Dash-FasAPI-Admin'
+# 应用代理路径
+APP_ROOT_PATH = ''
+# 应用主机
+APP_HOST = '0.0.0.0'
+# 应用端口
+APP_PORT = 9099
+# 应用版本
+APP_VERSION= '1.2.0'
+# 应用是否开启热重载
+APP_RELOAD = true
+
+# -------- Jwt配置 --------
+# Jwt秘钥
+JWT_SECRET_KEY = 'b01c66dc2c58dc6a0aabfe2144256be36226de378bf87f72c0c795dda67f4d55'
+# Jwt算法
+JWT_ALGORITHM = 'HS256'
+# 令牌过期时间
+JWT_EXPIRE_MINUTES = 1440
+# redis中令牌过期时间
+JWT_REDIS_EXPIRE_MINUTES = 30
+
+
+# -------- 数据库配置 --------
+# 数据库主机
+DB_HOST = '127.0.0.1'
+# 数据库端口
+DB_PORT = 3306
+# 数据库用户名
+DB_USERNAME = 'root'
+# 数据库密码
+DB_PASSWORD = 'mysqlroot'
+# 数据库名称
+DB_DATABASE = 'dash-fastapi'
+
+# -------- Redis配置 --------
+# Redis主机
+REDIS_HOST = '127.0.0.1'
+# Redis端口
+REDIS_PORT = 6379
+# Redis用户名
+REDIS_USERNAME = ''
+# Redis密码
+REDIS_PASSWORD = ''
+# Redis数据库
+REDIS_DATABASE = 2
\ No newline at end of file
diff --git a/dash-fastapi-backend/.env.prod b/dash-fastapi-backend/.env.prod
new file mode 100644
index 0000000000000000000000000000000000000000..bc743e925e08d3204581c2607ae33a8b0ad60212
--- /dev/null
+++ b/dash-fastapi-backend/.env.prod
@@ -0,0 +1,50 @@
+# -------- 应用配置 --------
+# 应用运行环境
+APP_ENV = 'prod'
+# 应用名称
+APP_NAME = 'Dash-FasAPI'
+# 应用代理路径
+APP_ROOT_PATH = '/prod-api'
+# 应用主机
+APP_HOST = '0.0.0.0'
+# 应用端口
+APP_PORT = 9099
+# 应用版本
+APP_VERSION= '1.2.0'
+# 应用是否开启热重载
+APP_RELOAD = false
+
+# -------- Jwt配置 --------
+# Jwt秘钥
+JWT_SECRET_KEY = 'b01c66dc2c58dc6a0aabfe2144256be36226de378bf87f72c0c795dda67f4d55'
+# Jwt算法
+JWT_ALGORITHM = 'HS256'
+# 令牌过期时间
+JWT_EXPIRE_MINUTES = 1440
+# redis中令牌过期时间
+JWT_REDIS_EXPIRE_MINUTES = 30
+
+
+# -------- 数据库配置 --------
+# 数据库主机
+DB_HOST = '127.0.0.1'
+# 数据库端口
+DB_PORT = 3306
+# 数据库用户名
+DB_USERNAME = 'root'
+# 数据库密码
+DB_PASSWORD = 'mysqlroot'
+# 数据库名称
+DB_DATABASE = 'dash-fastapi'
+
+# -------- Redis配置 --------
+# Redis主机
+REDIS_HOST = '127.0.0.1'
+# Redis端口
+REDIS_PORT = 6379
+# Redis用户名
+REDIS_USERNAME = ''
+# Redis密码
+REDIS_PASSWORD = ''
+# Redis数据库
+REDIS_DATABASE = 2
\ No newline at end of file
diff --git a/dash-fastapi-backend/app.py b/dash-fastapi-backend/app.py
index 93a8c2a6012bfb94aa3c7778bdc09a9ab53724d4..81d0bce88e71b07a7ae61766a3b5f44d7c4eccfb 100644
--- a/dash-fastapi-backend/app.py
+++ b/dash-fastapi-backend/app.py
@@ -18,6 +18,7 @@ from module_admin.controller.job_controller import jobController
from module_admin.controller.server_controller import serverController
from module_admin.controller.cache_controller import cacheController
from module_admin.controller.common_controller import commonController
+from config.env import AppConfig
from config.get_redis import RedisUtil
from config.get_db import init_create_table
from config.get_scheduler import SchedulerUtil
@@ -26,9 +27,10 @@ from utils.log_util import logger
from utils.common_util import worship
app = FastAPI(
- title='Dash-FastAPI',
- description='Dash-FastAPI接口文档',
- version='1.0.0',
+ title=AppConfig.app_name,
+ description=f'{AppConfig.app_name}接口文档',
+ version=AppConfig.app_version,
+ root_path=AppConfig.app_root_path,
)
# 前端页面url
@@ -49,14 +51,14 @@ app.add_middleware(
@app.on_event("startup")
async def startup_event():
- logger.info("Dash-FastAPI开始启动")
+ logger.info(f"{AppConfig.app_name}开始启动")
worship()
await init_create_table()
app.state.redis = await RedisUtil.create_redis_pool()
await RedisUtil.init_sys_dict(app.state.redis)
await RedisUtil.init_sys_config(app.state.redis)
await SchedulerUtil.init_system_scheduler()
- logger.info("Dash-FastAPI启动成功")
+ logger.info(f"{AppConfig.app_name}启动成功")
@app.on_event("shutdown")
@@ -103,4 +105,9 @@ app.include_router(cacheController, prefix="/monitor", tags=['系统监控-缓
app.include_router(commonController, prefix="/common", tags=['通用模块'])
if __name__ == '__main__':
- uvicorn.run(app='app:app', host="0.0.0.0", port=9099, reload=True)
+ uvicorn.run(
+ app='app:app',
+ host=AppConfig.app_host,
+ port=AppConfig.app_port,
+ reload=AppConfig.app_reload
+ )
diff --git a/dash-fastapi-backend/config/database.py b/dash-fastapi-backend/config/database.py
index a9acc4c4f06f77155e6cbe2feaf82c7a0a7babc9..8d2012fbcd07067aacb69682876e474444058ace 100644
--- a/dash-fastapi-backend/config/database.py
+++ b/dash-fastapi-backend/config/database.py
@@ -4,8 +4,8 @@ from sqlalchemy.orm import sessionmaker
from urllib.parse import quote_plus
from config.env import DataBaseConfig
-SQLALCHEMY_DATABASE_URL = f"mysql+pymysql://{DataBaseConfig.USERNAME}:{quote_plus(DataBaseConfig.PASSWORD)}@" \
- f"{DataBaseConfig.HOST}:{DataBaseConfig.PORT}/{DataBaseConfig.DB}"
+SQLALCHEMY_DATABASE_URL = f"mysql+pymysql://{DataBaseConfig.db_username}:{quote_plus(DataBaseConfig.db_password)}@" \
+ f"{DataBaseConfig.db_host}:{DataBaseConfig.db_port}/{DataBaseConfig.db_database}"
engine = create_engine(
SQLALCHEMY_DATABASE_URL, echo=True
diff --git a/dash-fastapi-backend/config/env.py b/dash-fastapi-backend/config/env.py
index be50c118b8042fbe6d0327c60c639173d2d64964..ce63d17aaac9cf10522806240d627fdd39e04505 100644
--- a/dash-fastapi-backend/config/env.py
+++ b/dash-fastapi-backend/config/env.py
@@ -1,36 +1,54 @@
import os
+import sys
+import argparse
+from pydantic import BaseSettings
+from functools import lru_cache
+from dotenv import load_dotenv
-class JwtConfig:
+class AppSettings(BaseSettings):
+ """
+ 应用配置
+ """
+ app_env: str = 'dev'
+ app_name: str = 'RuoYi-FasAPI'
+ app_root_path: str = '/dev-api'
+ app_host: str = '0.0.0.0'
+ app_port: int = 9099
+ app_version: str = '1.0.0'
+ app_reload: bool = True
+
+
+class JwtSettings(BaseSettings):
"""
Jwt配置
"""
- SECRET_KEY = "b01c66dc2c58dc6a0aabfe2144256be36226de378bf87f72c0c795dda67f4d55"
- ALGORITHM = "HS256"
- ACCESS_TOKEN_EXPIRE_MINUTES = 1440
- REDIS_TOKEN_EXPIRE_MINUTES = 30
+ jwt_secret_key: str = 'b01c66dc2c58dc6a0aabfe2144256be36226de378bf87f72c0c795dda67f4d55'
+ jwt_algorithm: str = 'HS256'
+ jwt_expire_minutes: int = 1440
+ jwt_redis_expire_minutes: int = 30
-class DataBaseConfig:
+class DataBaseSettings(BaseSettings):
"""
数据库配置
"""
- HOST = "127.0.0.1"
- PORT = 3306
- USERNAME = 'root'
- PASSWORD = 'mysqlroot'
- DB = 'dash-fastapi'
+ db_host: str = '127.0.0.1'
+ db_port: int = 3306
+ db_username: str = 'root'
+ db_password: str = 'mysqlroot'
+ db_database: str = 'ruoyi-fastapi'
-class RedisConfig:
+class RedisSettings(BaseSettings):
"""
Redis配置
"""
- HOST = "127.0.0.1"
- PORT = 6379
- USERNAME = ''
- PASSWORD = ''
- DB = 2
+ redis_host: str = '127.0.0.1'
+ redis_port: int = 6379
+ redis_username: str = ''
+ redis_password: str = ''
+ redis_database: int = 2
class CachePathConfig:
@@ -52,3 +70,82 @@ class RedisInitKeyConfig:
ACCOUNT_LOCK = {'key': 'account_lock', 'remark': '用户锁定'}
PASSWORD_ERROR_COUNT = {'key': 'password_error_count', 'remark': '密码错误次数'}
SMS_CODE = {'key': 'sms_code', 'remark': '短信验证码'}
+
+
+class GetConfig:
+ """
+ 获取配置
+ """
+
+ def __init__(self):
+ self.parse_cli_args()
+
+ @lru_cache()
+ def get_app_config(self):
+ """
+ 获取应用配置
+ """
+ # 实例化应用配置模型
+ return AppSettings()
+
+ @lru_cache()
+ def get_jwt_config(self):
+ """
+ 获取Jwt配置
+ """
+ # 实例化Jwt配置模型
+ return JwtSettings()
+
+ @lru_cache()
+ def get_database_config(self):
+ """
+ 获取数据库配置
+ """
+ # 实例化数据库配置模型
+ return DataBaseSettings()
+
+ @lru_cache()
+ def get_redis_config(self):
+ """
+ 获取Redis配置
+ """
+ # 实例化Redis配置模型
+ return RedisSettings()
+
+ @staticmethod
+ def parse_cli_args():
+ """
+ 解析命令行参数
+ """
+ if 'uvicorn' in sys.argv[0]:
+ # 使用uvicorn启动时,命令行参数需要按照uvicorn的文档进行配置,无法自定义参数
+ pass
+ else:
+ # 使用argparse定义命令行参数
+ parser = argparse.ArgumentParser(description='命令行参数')
+ parser.add_argument('--env', type=str, default='', help='运行环境')
+ # 解析命令行参数
+ args = parser.parse_args()
+ # 设置环境变量,如果未设置命令行参数,默认APP_ENV为dev
+ os.environ['APP_ENV'] = args.env if args.env else 'dev'
+ # 读取运行环境
+ run_env = os.environ.get('APP_ENV', '')
+ # 运行环境未指定时默认加载.env.dev
+ env_file = '.env.dev'
+ # 运行环境不为空时按命令行参数加载对应.env文件
+ if run_env != '':
+ env_file = f'.env.{run_env}'
+ # 加载配置
+ load_dotenv(env_file)
+
+
+# 实例化获取配置类
+get_config = GetConfig()
+# 应用配置
+AppConfig = get_config.get_app_config()
+# Jwt配置
+JwtConfig = get_config.get_jwt_config()
+# 数据库配置
+DataBaseConfig = get_config.get_database_config()
+# Redis配置
+RedisConfig = get_config.get_redis_config()
diff --git a/dash-fastapi-backend/config/get_redis.py b/dash-fastapi-backend/config/get_redis.py
index 2890d63c6cfce90a10ac9c5959b9695a35563501..4c3ef800f881cae013ac0d3a76590b98d5860ceb 100644
--- a/dash-fastapi-backend/config/get_redis.py
+++ b/dash-fastapi-backend/config/get_redis.py
@@ -20,11 +20,11 @@ class RedisUtil:
"""
logger.info("开始连接redis...")
redis = await aioredis.from_url(
- url=f"redis://{RedisConfig.HOST}",
- port=RedisConfig.PORT,
- username=RedisConfig.USERNAME,
- password=RedisConfig.PASSWORD,
- db=RedisConfig.DB,
+ url=f"redis://{RedisConfig.redis_host}",
+ port=RedisConfig.redis_port,
+ username=RedisConfig.redis_username,
+ password=RedisConfig.redis_password,
+ db=RedisConfig.redis_database,
encoding="utf-8",
decode_responses=True
)
diff --git a/dash-fastapi-backend/config/get_scheduler.py b/dash-fastapi-backend/config/get_scheduler.py
index af1c6334349e84b3c1ed6b25b62dfae7bd0030df..2e51af4c7b701cfb2c183c00492e070aa770ddad 100644
--- a/dash-fastapi-backend/config/get_scheduler.py
+++ b/dash-fastapi-backend/config/get_scheduler.py
@@ -70,11 +70,11 @@ job_stores = {
'sqlalchemy': SQLAlchemyJobStore(url=SQLALCHEMY_DATABASE_URL, engine=engine),
'redis': RedisJobStore(
**dict(
- host=RedisConfig.HOST,
- port=RedisConfig.PORT,
- username=RedisConfig.USERNAME,
- password=RedisConfig.PASSWORD,
- db=RedisConfig.DB
+ host=RedisConfig.redis_host,
+ port=RedisConfig.redis_port,
+ username=RedisConfig.redis_username,
+ password=RedisConfig.redis_password,
+ db=RedisConfig.redis_database
)
)
}
diff --git a/dash-fastapi-backend/module_admin/annotation/log_annotation.py b/dash-fastapi-backend/module_admin/annotation/log_annotation.py
index c2d88a69e65078857c812a2b9bf87d63554085f1..f1e0f706a1bd35d018988a44769c6c39a23d3492 100644
--- a/dash-fastapi-backend/module_admin/annotation/log_annotation.py
+++ b/dash-fastapi-backend/module_admin/annotation/log_annotation.py
@@ -12,6 +12,7 @@ from typing import Optional
from module_admin.service.login_service import get_current_user
from module_admin.service.log_service import OperationLogService, LoginLogService
from module_admin.entity.vo.log_vo import OperLogModel, LogininforModel
+from config.env import AppConfig
def log_decorator(title: str, business_type: int, log_type: Optional[str] = 'operation'):
@@ -48,7 +49,7 @@ def log_decorator(title: str, business_type: int, log_type: Optional[str] = 'ope
# 获取请求的url
oper_url = request.url.path
# 获取请求的ip及ip归属区域
- oper_ip = request.headers.get('remote_addr')
+ oper_ip = request.headers.get('X-Forwarded-For') if AppConfig.app_env == 'prod' else request.headers.get('remote_addr')
oper_location = '内网IP'
try:
if oper_ip != '127.0.0.1' and oper_ip != 'localhost':
diff --git a/dash-fastapi-backend/module_admin/controller/login_controller.py b/dash-fastapi-backend/module_admin/controller/login_controller.py
index 19ff188ef2e5f3a1d807503bd3b60330be2f387d..191d8715c0b9d251af4c551eef70cd855b5b33fd 100644
--- a/dash-fastapi-backend/module_admin/controller/login_controller.py
+++ b/dash-fastapi-backend/module_admin/controller/login_controller.py
@@ -32,7 +32,7 @@ async def login(request: Request, form_data: CustomOAuth2PasswordRequestForm = D
except LoginException as e:
return response_400(data="", message=e.message)
try:
- access_token_expires = timedelta(minutes=JwtConfig.ACCESS_TOKEN_EXPIRE_MINUTES)
+ access_token_expires = timedelta(minutes=JwtConfig.jwt_expire_minutes)
session_id = str(uuid.uuid4())
access_token = create_access_token(
data={
@@ -45,10 +45,10 @@ async def login(request: Request, form_data: CustomOAuth2PasswordRequestForm = D
expires_delta=access_token_expires
)
await request.app.state.redis.set(f"{RedisInitKeyConfig.ACCESS_TOKEN.get('key')}:{session_id}", access_token,
- ex=timedelta(minutes=JwtConfig.REDIS_TOKEN_EXPIRE_MINUTES))
+ ex=timedelta(minutes=JwtConfig.jwt_redis_expire_minutes))
# 此方法可实现同一账号同一时间只能登录一次
# await request.app.state.redis.set(f"{RedisInitKeyConfig.ACCESS_TOKEN.get('key')}:{result[0].user_id}", access_token,
- # ex=timedelta(minutes=JwtConfig.REDIS_TOKEN_EXPIRE_MINUTES))
+ # ex=timedelta(minutes=JwtConfig.jwt_redis_expire_minutes))
logger.info('登录成功')
# 判断请求是否来自于api文档,如果是返回指定格式的结果,用于修复api文档认证成功后token显示undefined的bug
request_from_swagger = request.headers.get('referer').endswith('docs') if request.headers.get('referer') else False
@@ -107,7 +107,7 @@ async def get_login_user_info(request: Request, current_user: CurrentUserInfoSer
@loginController.post("/logout", dependencies=[Depends(get_current_user), Depends(CheckUserInterfaceAuth('common'))])
async def logout(request: Request, token: Optional[str] = Depends(oauth2_scheme), query_db: Session = Depends(get_db)):
try:
- payload = jwt.decode(token, JwtConfig.SECRET_KEY, algorithms=[JwtConfig.ALGORITHM])
+ payload = jwt.decode(token, JwtConfig.jwt_secret_key, algorithms=[JwtConfig.jwt_algorithm])
session_id: str = payload.get("session_id")
await logout_services(request, session_id)
logger.info('退出成功')
diff --git a/dash-fastapi-backend/module_admin/service/login_service.py b/dash-fastapi-backend/module_admin/service/login_service.py
index ca6f8db254b8059e409691656c3ad7dab6668639..53b133af0c8ad6cf1d94edb93d356edae3d23c20 100644
--- a/dash-fastapi-backend/module_admin/service/login_service.py
+++ b/dash-fastapi-backend/module_admin/service/login_service.py
@@ -59,7 +59,7 @@ async def get_current_user(request: Request = Request, token: str = Depends(oaut
try:
if token.startswith('Bearer'):
token = token.split(' ')[1]
- payload = jwt.decode(token, JwtConfig.SECRET_KEY, algorithms=[JwtConfig.ALGORITHM])
+ payload = jwt.decode(token, JwtConfig.jwt_secret_key, algorithms=[JwtConfig.jwt_algorithm])
user_id: str = payload.get("user_id")
session_id: str = payload.get("session_id")
if user_id is None:
@@ -78,9 +78,9 @@ async def get_current_user(request: Request = Request, token: str = Depends(oaut
# redis_token = await request.app.state.redis.get(f"{RedisInitKeyConfig.ACCESS_TOKEN.get('key')}:{user.user_basic_info.user_id}")
if token == redis_token:
await request.app.state.redis.set(f"{RedisInitKeyConfig.ACCESS_TOKEN.get('key')}:{session_id}", redis_token,
- ex=timedelta(minutes=JwtConfig.REDIS_TOKEN_EXPIRE_MINUTES))
+ ex=timedelta(minutes=JwtConfig.jwt_redis_expire_minutes))
# await request.app.state.redis.set(f"{RedisInitKeyConfig.ACCESS_TOKEN.get('key')}:{user.user_basic_info.user_id}", redis_token,
- # ex=timedelta(minutes=JwtConfig.REDIS_TOKEN_EXPIRE_MINUTES))
+ # ex=timedelta(minutes=JwtConfig.jwt_redis_expire_minutes))
return CurrentUserInfoServiceResponse(
user=user.user_basic_info,
@@ -227,7 +227,7 @@ def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None
else:
expire = datetime.utcnow() + timedelta(minutes=15)
to_encode.update({"exp": expire})
- encoded_jwt = jwt.encode(to_encode, JwtConfig.SECRET_KEY, algorithm=JwtConfig.ALGORITHM)
+ encoded_jwt = jwt.encode(to_encode, JwtConfig.jwt_secret_key, algorithm=JwtConfig.jwt_algorithm)
return encoded_jwt
diff --git a/dash-fastapi-backend/module_admin/service/online_service.py b/dash-fastapi-backend/module_admin/service/online_service.py
index 47277ea8b58af8a36751abc9bd3e738d9d24a3d4..6ef9080faf25bee31f17ed252d7e130eae4a27d2 100644
--- a/dash-fastapi-backend/module_admin/service/online_service.py
+++ b/dash-fastapi-backend/module_admin/service/online_service.py
@@ -23,7 +23,7 @@ class OnlineService:
access_token_values_list = [await request.app.state.redis.get(key) for key in access_token_keys]
online_info_list = []
for item in access_token_values_list:
- payload = jwt.decode(item, JwtConfig.SECRET_KEY, algorithms=[JwtConfig.ALGORITHM])
+ payload = jwt.decode(item, JwtConfig.jwt_secret_key, algorithms=[JwtConfig.jwt_algorithm])
online_dict = dict(
session_id=payload.get('session_id'),
user_name=payload.get('user_name'),
diff --git a/dash-fastapi-frontend/.env.dev b/dash-fastapi-frontend/.env.dev
new file mode 100644
index 0000000000000000000000000000000000000000..6f368488e29aa0104b045df4a94c2e977366e2bb
--- /dev/null
+++ b/dash-fastapi-frontend/.env.dev
@@ -0,0 +1,22 @@
+# -------- 应用配置 --------
+# 应用运行环境
+APP_ENV = 'dev'
+# 应用名称
+APP_NAME = '通用后台管理系统'
+# 应用请求后端url
+APP_BASE_URL = 'http://127.0.0.1:9099'
+# 后端是否使用代理模式
+APP_IS_PROXY = false
+# 应用代理路径
+APP_PROXY_PATH = ''
+# 应用秘钥
+APP_SECRET_KEY = 'Dash-FastAPI-Admin'
+# 应用主机
+APP_HOST = '0.0.0.0'
+# 应用端口
+APP_PORT = 8088
+# 应用是否开启debug模式
+APP_DEBUG = true
+# flask-compress压缩配置
+APP_COMPRESS_ALGORITHM = 'br'
+APP_COMPRESS_BR_LEVEL = 11
\ No newline at end of file
diff --git a/dash-fastapi-frontend/.env.prod b/dash-fastapi-frontend/.env.prod
new file mode 100644
index 0000000000000000000000000000000000000000..72685a3acee114f01281576a117ca8d265cd31ee
--- /dev/null
+++ b/dash-fastapi-frontend/.env.prod
@@ -0,0 +1,22 @@
+# -------- 应用配置 --------
+# 应用运行环境
+APP_ENV = 'prod'
+# 应用名称
+APP_NAME = '通用后台管理系统'
+# 应用请求后端url
+APP_BASE_URL = 'http://127.0.0.1:9099'
+# 后端是否使用代理模式
+APP_IS_PROXY = true
+# 应用代理路径
+APP_PROXY_PATH = '/prod-api'
+# 应用秘钥
+APP_SECRET_KEY = 'Dash-FastAPI-Admin'
+# 应用主机
+APP_HOST = '0.0.0.0'
+# 应用端口
+APP_PORT = 8088
+# 应用是否开启debug模式
+APP_DEBUG = false
+# flask-compress压缩配置
+APP_COMPRESS_ALGORITHM = 'br'
+APP_COMPRESS_BR_LEVEL = 11
\ No newline at end of file
diff --git a/dash-fastapi-frontend/app.py b/dash-fastapi-frontend/app.py
index 029167cc9467901d64d6dba9811a86d9dfcbc27c..e1d840df98a90a7ab8c2af7b5c8685d1486eaaca 100644
--- a/dash-fastapi-frontend/app.py
+++ b/dash-fastapi-frontend/app.py
@@ -8,6 +8,7 @@ from flask import session
from operator import itemgetter
from server import app
+from config.env import AppConfig
from config.global_config import RouterConfig
from store.store import render_store_container
@@ -256,4 +257,4 @@ def router(pathname, url_trigger, session_token):
if __name__ == '__main__':
- app.run(host='0.0.0.0', port=8088, debug=True)
+ app.run(host=AppConfig.app_host, port=AppConfig.app_port, debug=AppConfig.app_debug)
diff --git a/dash-fastapi-frontend/config/env.py b/dash-fastapi-frontend/config/env.py
new file mode 100644
index 0000000000000000000000000000000000000000..afa30bbf1529c01671370a20b612ca43c74f17c6
--- /dev/null
+++ b/dash-fastapi-frontend/config/env.py
@@ -0,0 +1,67 @@
+import os
+import argparse
+from pydantic import BaseSettings
+from functools import lru_cache
+from dotenv import load_dotenv
+
+
+class AppSettings(BaseSettings):
+ """
+ 应用配置
+ """
+ app_env: str = 'dev'
+ app_name: str = '通用后台管理系统'
+ app_base_url: str = 'http://127.0.0.1:9099'
+ app_proxy_path: str = '/dev-api'
+ app_is_proxy: bool = False
+ app_secret_key: str = 'Dash-FastAPI-Admin'
+ app_host: str = '0.0.0.0'
+ app_port: int = 8088
+ app_debug: bool = True
+ app_compress_algorithm = 'br'
+ app_compress_br_level = 11
+
+
+class GetConfig:
+ """
+ 获取配置
+ """
+
+ def __init__(self):
+ self.parse_cli_args()
+
+ @lru_cache()
+ def get_app_config(self):
+ """
+ 获取应用配置
+ """
+ # 实例化应用配置模型
+ return AppSettings()
+
+ @staticmethod
+ def parse_cli_args():
+ """
+ 解析命令行参数
+ """
+ # 使用argparse定义命令行参数
+ parser = argparse.ArgumentParser(description='命令行参数')
+ parser.add_argument('--env', type=str, default='', help='运行环境')
+ # 解析命令行参数
+ args = parser.parse_args()
+ # 设置环境变量,如果未设置命令行参数,默认APP_ENV为dev
+ os.environ['APP_ENV'] = args.env if args.env else 'dev'
+ # 读取运行环境
+ run_env = os.environ.get('APP_ENV', '')
+ # 运行环境未指定时默认加载.env.dev
+ env_file = '.env.dev'
+ # 运行环境不为空时按命令行参数加载对应.env文件
+ if run_env != '':
+ env_file = f'.env.{run_env}'
+ # 加载配置
+ load_dotenv(env_file)
+
+
+# 实例化获取配置类
+get_config = GetConfig()
+# 应用配置
+AppConfig = get_config.get_app_config()
diff --git a/dash-fastapi-frontend/config/global_config.py b/dash-fastapi-frontend/config/global_config.py
index 3103078f851308a2ac3fbc8ad308879b38a86644..2485a4f30eb23513db3dc01c050ec42abdfcca0d 100644
--- a/dash-fastapi-frontend/config/global_config.py
+++ b/dash-fastapi-frontend/config/global_config.py
@@ -1,4 +1,5 @@
import os
+from config.env import AppConfig
class PathConfig:
@@ -21,7 +22,7 @@ class RouterConfig:
class ApiBaseUrlConfig:
# api基本url
- BaseUrl = 'http://127.0.0.1:9099'
+ BaseUrl = AppConfig.app_base_url + AppConfig.app_proxy_path if AppConfig.app_is_proxy else AppConfig.app_base_url
class IconConfig:
diff --git a/dash-fastapi-frontend/server.py b/dash-fastapi-frontend/server.py
index d1fc8eaecebec337b66cd76579f2c0b0e8f5c0b8..ada6f7bccc2503b8c9bcd072c15dd7719fa0f9ce 100644
--- a/dash-fastapi-frontend/server.py
+++ b/dash-fastapi-frontend/server.py
@@ -4,6 +4,7 @@ import time
from loguru import logger
from flask import request, session
from user_agents import parse
+from config.env import AppConfig
from config.global_config import PathConfig
app = dash.Dash(
@@ -15,12 +16,12 @@ app = dash.Dash(
server = app.server
-app.title = '通用后台管理系统'
+app.title = AppConfig.app_name
# 配置密钥
-app.server.secret_key = 'Dash-FastAPI'
-app.server.config['COMPRESS_ALGORITHM'] = 'br'
-app.server.config['COMPRESS_BR_LEVEL'] = 8
+app.server.secret_key = AppConfig.app_secret_key
+app.server.config['COMPRESS_ALGORITHM'] = AppConfig.app_compress_algorithm
+app.server.config['COMPRESS_BR_LEVEL'] = AppConfig.app_compress_br_level
log_time = time.strftime("%Y%m%d", time.localtime())
# sys_log_file_path = os.path.join(PathConfig.ABS_ROOT_PATH, 'log', 'sys_log', f'sys_request_log_{log_time}.log')
@@ -34,17 +35,18 @@ logger.add(api_log_file_path, filter=lambda x: '[api]' in x['message'],
# 获取用户浏览器信息
@server.before_request
def get_user_agent_info():
+ request_addr = request.headers.get("X-Forwarded-For") if AppConfig.app_env == 'prod' else request.remote_addr
user_string = str(request.user_agent)
user_agent = parse(user_string)
bw = user_agent.browser.family
bw_version = user_agent.browser.version[0]
if bw == 'IE':
logger.warning("[sys]请求人:{}||请求IP:{}||请求方法:{}||请求Data:{}",
- session.get('name'), request.remote_addr, request.method, '用户使用IE内核')
+ session.get('name'), request_addr, request.method, '用户使用IE内核')
return "
请不要使用IE浏览器或360浏览器兼容模式
"
if bw_version < 71:
logger.warning("[sys]请求人:{}||请求IP:{}||请求方法:{}||请求Data:{}",
- session.get('name'), request.remote_addr, request.method, '用户Chrome内核版本太低')
+ session.get('name'), request_addr, request.method, '用户Chrome内核版本太低')
return "Chrome内核版本号太低,请升级浏览器
" \
"点击此处可下载最新版Chrome浏览器
"
diff --git a/dash-fastapi-frontend/utils/request.py b/dash-fastapi-frontend/utils/request.py
index 08e31fc800817823a128247b575c25d6848f1df1..a605dadbbc5691cd22f9d941d0dc4e26073a4fc0 100644
--- a/dash-fastapi-frontend/utils/request.py
+++ b/dash-fastapi-frontend/utils/request.py
@@ -1,6 +1,7 @@
import requests
from typing import Optional
from flask import session, request
+from config.env import AppConfig
from config.global_config import ApiBaseUrlConfig
from server import logger
@@ -11,11 +12,12 @@ def api_request(method: str, url: str, is_headers: bool, params: Optional[dict]
method = method.lower().strip()
user_agent = request.headers.get('User-Agent')
authorization = session.get('Authorization') if session.get('Authorization') else ''
+ remote_addr = request.headers.get("X-Forwarded-For") if AppConfig.app_env == 'prod' else request.remote_addr
if is_headers:
- api_headers = {'Authorization': 'Bearer ' + authorization, 'remote_addr': request.remote_addr,
+ api_headers = {'Authorization': 'Bearer ' + authorization, 'remote_addr': remote_addr,
'User-Agent': user_agent}
else:
- api_headers = {'remote_addr': request.remote_addr, 'User-Agent': user_agent}
+ api_headers = {'remote_addr': remote_addr, 'User-Agent': user_agent}
try:
if method == 'get':
response = requests.get(url=api_url, params=params, data=data, json=json, headers=api_headers,
diff --git a/dash-fastapi-frontend/wsgi.py b/dash-fastapi-frontend/wsgi.py
index 3b653a0e1cbbddb92fe6af64b107dca34c44f079..4e50b7779111425dcb51975ae720aab0cdcec458 100644
--- a/dash-fastapi-frontend/wsgi.py
+++ b/dash-fastapi-frontend/wsgi.py
@@ -1,8 +1,9 @@
from waitress import serve
from app import app
+from config.env import AppConfig
serve(
app.server,
- host='0.0.0.0',
- port=8088
+ host=AppConfig.app_host,
+ port=AppConfig.app_port
)