Browse Source

feat: 新增环境变量配置,支持使用命令启动对应的应用环境

master
insistence 1 year ago
parent
commit
dd98031e14
  1. 50
      ruoyi-fastapi-backend/.env.dev
  2. 50
      ruoyi-fastapi-backend/.env.prod
  3. 19
      ruoyi-fastapi-backend/app.py
  4. 4
      ruoyi-fastapi-backend/config/database.py
  5. 143
      ruoyi-fastapi-backend/config/env.py
  6. 10
      ruoyi-fastapi-backend/config/get_redis.py
  7. 10
      ruoyi-fastapi-backend/config/get_scheduler.py
  8. 8
      ruoyi-fastapi-backend/module_admin/controller/login_controller.py
  9. 10
      ruoyi-fastapi-backend/module_admin/service/login_service.py
  10. 2
      ruoyi-fastapi-backend/module_admin/service/online_service.py

50
ruoyi-fastapi-backend/.env.dev

@ -0,0 +1,50 @@
# -------- 应用配置 --------
# 应用运行环境
APP_ENV = 'dev'
# 应用名称
APP_NAME = 'RuoYi-FasAPI'
# 应用代理路径
APP_ROOT_PATH = '/dev-api'
# 应用主机
APP_HOST = '0.0.0.0'
# 应用端口
APP_PORT = 9099
# 应用版本
APP_VERSION= '1.0.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 = 'ruoyi-fastapi'
# -------- Redis配置 --------
# Redis主机
REDIS_HOST = '127.0.0.1'
# Redis端口
REDIS_PORT = 6379
# Redis用户名
REDIS_USERNAME = ''
# Redis密码
REDIS_PASSWORD = ''
# Redis数据库
REDIS_DATABASE = 2

50
ruoyi-fastapi-backend/.env.prod

@ -0,0 +1,50 @@
# -------- 应用配置 --------
# 应用运行环境
APP_ENV = 'prod'
# 应用名称
APP_NAME = 'RuoYi-FasAPI'
# 应用代理路径
APP_ROOT_PATH = '/prod-api'
# 应用主机
APP_HOST = '0.0.0.0'
# 应用端口
APP_PORT = 9099
# 应用版本
APP_VERSION= '1.0.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 = 'root'
# 数据库名称
DB_DATABASE = 'ruoyi-fastapi'
# -------- Redis配置 --------
# Redis主机
REDIS_HOST = '127.0.0.1'
# Redis端口
REDIS_PORT = 6379
# Redis用户名
REDIS_USERNAME = ''
# Redis密码
REDIS_PASSWORD = ''
# Redis数据库
REDIS_DATABASE = 2

19
ruoyi-fastapi-backend/app.py

@ -20,7 +20,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 UploadConfig
from config.env import AppConfig, UploadConfig
from config.get_redis import RedisUtil
from config.get_db import init_create_table
from config.get_scheduler import SchedulerUtil
@ -31,23 +31,23 @@ from utils.common_util import worship
@asynccontextmanager
async def lifespan(app: FastAPI):
logger.info("RuoYi-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("RuoYi-FastAPI启动成功")
logger.info(f"{AppConfig.app_name}启动成功")
yield
await RedisUtil.close_redis_pool(app)
await SchedulerUtil.close_system_scheduler()
app = FastAPI(
title='RuoYi-FastAPI',
description='RuoYi-FastAPI接口文档',
version='1.0.0',
title=AppConfig.app_name,
description=f'{AppConfig.app_name}接口文档',
version=AppConfig.app_version,
lifespan=lifespan
)
@ -66,11 +66,8 @@ app.add_middleware(
allow_headers=["*"],
)
# 实例化UploadConfig,确保应用启动时上传目录存在
upload_config = UploadConfig()
# 挂载静态文件路径
app.mount(f"{upload_config.UPLOAD_PREFIX}", StaticFiles(directory=f"{upload_config.UPLOAD_PATH}"), name="profile")
app.mount(f"{UploadConfig.UPLOAD_PREFIX}", StaticFiles(directory=f"{UploadConfig.UPLOAD_PATH}"), name="profile")
# 自定义token检验异常
@ -116,4 +113,4 @@ for controller in controller_list:
app.include_router(router=controller.get('router'), tags=controller.get('tags'))
if __name__ == '__main__':
uvicorn.run(app='app:app', host="0.0.0.0", port=9099, root_path='/dev-api', reload=True)
uvicorn.run(app='app:app', host=AppConfig.app_host, port=AppConfig.app_port, root_path=AppConfig.app_root_path, reload=AppConfig.app_reload)

4
ruoyi-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

143
ruoyi-fastapi-backend/config/env.py

@ -1,39 +1,57 @@
import os
import sys
import argparse
from pydantic_settings 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 = 'ruoyi-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 UploadConfig:
class UploadSettings:
"""
上传配置
"""
@ -80,3 +98,92 @@ 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()
@lru_cache()
def get_upload_config(self):
"""
获取数据库配置
"""
# 实例上传配置
return UploadSettings()
@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()
# 设置环境变量
os.environ['APP_ENV'] = args.env
# 读取运行环境
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()
# 上传配置
UploadConfig = get_config.get_upload_config()

10
ruoyi-fastapi-backend/config/get_redis.py

@ -19,11 +19,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
)

10
ruoyi-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
)
)
}

8
ruoyi-fastapi-backend/module_admin/controller/login_controller.py

@ -29,7 +29,7 @@ async def login(request: Request, form_data: CustomOAuth2PasswordRequestForm = D
except LoginException as e:
return ResponseUtil.failure(msg=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 = LoginService.create_access_token(
data={
@ -42,10 +42,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
@ -115,7 +115,7 @@ async def forget_user_pwd(request: Request, forget_user: ResetUserModel, query_d
@loginController.post("/logout")
async def logout(request: Request, token: Optional[str] = Depends(oauth2_scheme)):
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('退出成功')

10
ruoyi-fastapi-backend/module_admin/service/login_service.py

@ -124,9 +124,9 @@ class LoginService:
if expires_delta:
expire = datetime.utcnow() + expires_delta
else:
expire = datetime.utcnow() + timedelta(minutes=15)
expire = datetime.utcnow() + timedelta(minutes=30)
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
@classmethod
@ -146,7 +146,7 @@ class LoginService:
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:
@ -165,9 +165,9 @@ class LoginService:
# 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))
role_id_list = [item.role_id for item in query_user.get('user_role_info')]
if 1 in role_id_list:

2
ruoyi-fastapi-backend/module_admin/service/online_service.py

@ -25,7 +25,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(
token_id=payload.get('session_id'),
user_name=payload.get('user_name'),

Loading…
Cancel
Save