zhaoqingang
2025-04-01 6846a4c98a793e74ae17b47f04a0ff8b210aeb24
授权license
12个文件已修改
1个文件已删除
2个文件已添加
278 ■■■■ 已修改文件
app/api/__init__.py 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/api/auth.py 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/api/system.py 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/api/v2/public_api.py 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/config/const.py 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/config/env_conf/system.yaml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/init_config/init_run_data.py 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/models/system.py 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/service/pom/public_key.pem 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/service/system.py 51 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/service/v2/initialize_data.py 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/task/sync_resources.py 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/task/sync_system.py 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/utils/common.py 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main.py 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/api/__init__.py
@@ -68,6 +68,14 @@
def get_current_user(token: str = Depends(oauth2_scheme)):
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        expired_time = payload.get("lex")
        if not expired_time:
            raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED,  detail="令牌无效或已过期",
            headers={"WWW-Authenticate": "Bearer"})
        if datetime.strptime(expired_time, "%Y-%m-%d %H:%M:%S") < datetime.now():
            raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED,  detail="系统授权已过期!",
            headers={"WWW-Authenticate": "Bearer"})
        username: str = payload.get("sub")
        if username is None:
            raise HTTPException(
app/api/auth.py
@@ -6,7 +6,8 @@
from sqlalchemy.ext.asyncio import AsyncSession
from app.api import Response, pwd_context, get_current_user
from app.config.config import settings
from app.config.const import chat_server, RAGFLOW, workflow_server, DIFY, TMP_DICT
from app.config.const import chat_server, RAGFLOW, workflow_server, DIFY, TMP_DICT, SYSTEM_ID, SYSTEM_STATUS_ON
from app.models import SystemDataModel
from app.models.app_token_model import AppToken
from app.models.base_model import get_db
from app.models.postgresql_base_model import get_pdb
@@ -130,8 +131,11 @@
        except Exception as e:
            return Response(code=500, msg=f"Failed to login with {app['id']}: {str(e)}")
    """
    system = db.query(SystemDataModel).filter_by(id=SYSTEM_ID).first()
    if not system or system.status != SYSTEM_STATUS_ON:
        return Response(code=400, msg="系统状态异常,请授权激活后操作!")
    # 创建本地token
    access_token = create_access_token(data={"sub": user.username, "user_id": user.id})
    access_token = create_access_token(data={"sub": user.username, "user_id": user.id, "lex": system.expired_at.strftime('%Y-%m-%d %H:%M:%S')})
    # await update_token(db, user.id, access_token, token_dict)
    # await update_user_token(db, user.id, token_dict)
app/api/system.py
@@ -4,9 +4,10 @@
from app.api import Response, get_current_user
from app.models.base_model import get_db
from app.models.role_model import RoleData, RoleModel
from app.models.system import SystemData
from app.models.system import SystemData, SystemLicense
from app.models.user_model import UserModel
from app.service.system import services_get_system_data, services_update_system_data, service_upload_logo_image
from app.service.system import services_get_system_data, services_update_system_data, service_upload_logo_image, \
    services_update_system_license
system_router = APIRouter()
@@ -33,3 +34,13 @@
    if not file_name:
        return Response(code=500, msg="failed", data={"logo": ""})
    return Response(code=200, msg="successfully", data={"logo": file_name})
@system_router.put("/license", response_model=Response)
async def api_update_system_license(system: SystemLicense, db=Depends(get_db)):
    msg = await services_update_system_license(db, system.licenseCode)
    if msg:
        return Response(code=400, msg=msg, data={})
    return Response(code=200, msg="successfully", data={})
app/api/v2/public_api.py
@@ -13,7 +13,7 @@
from app.models.public_api_model import DfToken
from app.service.v2.api_token import DfTokenDao
from app.service.v2.initialize_data import dialog_menu_sync, create_menu_sync, user_update_app
from app.task.sync_resources import sync_knowledge, sync_dialog, sync_agent, sync_llm, sync_resource
# from app.task.sync_resources import sync_knowledge, sync_dialog, sync_agent, sync_llm, sync_resource
from fastapi import Depends, APIRouter, File, UploadFile
from sqlalchemy.orm import Session
from app.config.const import smart_message_error, http_400, http_500, http_200, complex_dialog_chat
app/config/const.py
@@ -114,6 +114,9 @@
###-------------------------------system-------------------------------------------------
SYSTEM_ID = 1
SYSTEM_STATUS_EXPIRED = 2
SYSTEM_STATUS_ON = 1
SYSTEM_STATUS_OFF = 0
### --------------------------------complex mode----------------------------------------------
complex_dialog_chat = 1 # 文档和基础对话
app/config/env_conf/system.yaml
@@ -1,3 +1,4 @@
smart_system:
  title: SmartAI大模型平台
  desc: SmartAI大模型平台
  version: 1.0.3
app/init_config/init_run_data.py
@@ -1,6 +1,6 @@
from app.models.base_model import SessionLocal
from app.service.v2.initialize_data import dialog_menu_sync, default_group_sync, default_role_sync, \
    basic_agent_sync, admin_account_sync, sync_rg_api_token, sync_complex_api_token
    basic_agent_sync, admin_account_sync, sync_rg_api_token, sync_complex_api_token, system_license_sync
from app.task.sync_account_token import sync_token
@@ -15,6 +15,7 @@
        await sync_rg_api_token(db)  # rg token
        await sync_token()  # 账号token登录
        await sync_complex_api_token(db)  # 账号token登录
        await system_license_sync(db) # 同步系统license
    except Exception as e:
        print(e)
app/models/system.py
@@ -12,6 +12,11 @@
    id = Column(Integer, primary_key=True, index=True)
    title = Column(String(255))
    desc = Column(String(1000))
    version = Column(String(32))
    machine_id = Column(String(255))
    license_code = Column(String(1000))
    status = Column(Integer, default=0)
    expired_at = Column(DateTime)
    created_at = Column(DateTime, default=datetime.now())
    updated_at = Column(DateTime, default=datetime.now(), onupdate=datetime.now())
@@ -21,6 +26,11 @@
            # 'id': self.id,
            'title': self.title,
            'desc': self.desc,
            'version': self.version,
            'machine_id': self.machine_id,
            'license_code': self.license_code,
            'status': self.status,
            'expired_at': self.expired_at.strftime('%Y-%m-%d %H:%M') if self.expired_at else '',
        }
    def __repr__(self):
@@ -32,3 +42,7 @@
    title: str
    desc: str
    logo: str
class SystemLicense(BaseModel):
    licenseCode: str
app/service/pom/public_key.pem
New file
@@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8Jak4kGIkOE2kyI0oTcb
w3yk7OfZ78g1RGvxKlYbKWz93Prxi1pvywXHOnrL/IYDCaNFOybFy5aMbqqvqXOx
0LBCqwmB9F07AiEysmhH5m5OxlS9XsxGZb1WeRmobRbge3Hxl59DmUKvD/7Gdsre
JnDeSWxeaS/zIqLVUsvV3301B08biIywMAKamBQyuJNTPK1ir8iy6peSLPi022zk
Nl+Rm4ToOrF00oqwB8z5BOTdDcJW/eFlieOyTnWSAFBTIXAB9uqZSjn37kyLKYDh
yVqB71T/wQvMRip4PPFpCE4UCGGhLHHsKPhtCgxHj6YqE7vUCuGBXP/aagzpWC/H
ywIDAQAB
-----END PUBLIC KEY-----
app/service/system.py
@@ -1,15 +1,20 @@
import os
import shutil
import uuid
from datetime import datetime
import yaml
from fastapi import UploadFile
from datetime import datetime
from fastapi import UploadFile
from Log import logger
from app.api import pwd_context
from app.config.const import SYSTEM_ID, ENV_CONF_PATH, APP_STATIC_PATH
from app.config.const import SYSTEM_ID, ENV_CONF_PATH, APP_STATIC_PATH, APP_SERVICE_PATH, SYSTEM_STATUS_ON
from app.models.system import SystemDataModel
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import hashes
import base64
import json
from app.utils.common import get_machine_id
async def services_get_system_data(db):
@@ -18,7 +23,7 @@
        with open(os.path.join(ENV_CONF_PATH, "system.yaml"), 'r', encoding='utf-8') as file:
            # 加载JSON数据
            config = yaml.safe_load(file)
            system = SystemDataModel(id=SYSTEM_ID, title=config["smart_system"]["title"], desc=config["smart_system"]["desc"])
            system = SystemDataModel(id=SYSTEM_ID, title=config["smart_system"]["title"], desc=config["smart_system"]["desc"], version=config["smart_system"]["version"])
            db.add(system)
            db.commit()
            db.refresh(system)
@@ -53,3 +58,37 @@
    except Exception as e:
        logger.error(f"保存失败: {str(e)}")
        return ""
async def services_update_system_license(db, license_code):
    try:
        with open(os.path.join(APP_SERVICE_PATH, "pom/public_key.pem"), "rb") as f:
            public_key = serialization.load_pem_public_key(f.read())
        license_data, signature = base64.b64decode(license_code).split(b"-----", 1)
        # print(license_data)
        public_key.verify(
            signature,
            license_data,
            padding.PSS(
                mgf=padding.MGF1(hashes.SHA256()),
                salt_length=padding.PSS.MAX_LENGTH
            ),
            hashes.SHA256()
        )
        license_dict = json.loads(license_data.decode('utf-8'))
        # print(license_dict)
        expiration_date = datetime.fromisoformat(license_dict['expiration_date'])
        if expiration_date < datetime.now():
            return "授权码已过期"
        system = db.query(SystemDataModel).filter_by(id=SYSTEM_ID).first()
        if license_dict['machine_id'] != get_machine_id() or system.machine_id != license_dict['machine_id']:
            return "授权码无效"
        system.license_code = license_code
        system.expired_at = expiration_date
        system.status = SYSTEM_STATUS_ON
        system.updated_at = datetime.now()
        # db.query(SystemDataModel).filter_by(id=SYSTEM_ID).update({"license_code": license_code, "expired_at": expiration_date, "status": 1, "updated_at": datetime.now()})
        db.commit()
        return ""
    except Exception as e:
        return f"验证失败: {str(e)}"
app/service/v2/initialize_data.py
@@ -10,9 +10,9 @@
from app.config.agent_base_url import RG_APP_TOKEN_LIST, RG_APP_NEW_TOKEN, DF_CHAT_API_KEY
# from app.api import pwd_context
from app.config.const import DIFY, ENV_CONF_PATH, RAGFLOW, smart_server, chat_server, workflow_server, TMP_DICT, \
    rg_api_token, Dialog_STATSU_ON
    rg_api_token, Dialog_STATSU_ON, SYSTEM_ID
from app.models import MenuCapacityModel, WebMenuModel, GroupModel, RoleModel, DialogModel, UserModel, UserAppModel, \
    cipher_suite, UserTokenModel, ApiTokenModel, ComplexChatModel
    cipher_suite, UserTokenModel, ApiTokenModel, ComplexChatModel, SystemDataModel
from app.service.auth import UserAppDao
from app.service.bisheng import BishengService
from app.service.difyService import DifyService
@@ -22,6 +22,7 @@
from app.service.v2.app_register import AppRegisterDao
from app.config.config import settings
from app.service.v2.chat import get_app_token
from app.utils.common import get_machine_id
from app.utils.password_handle import generate_password, password_encrypted, password_decrypted
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
@@ -427,4 +428,21 @@
    except Exception as e:
        print(e)
        db.rollback()
        db.rollback()
async def system_license_sync(db):
    with open(os.path.join(ENV_CONF_PATH, "system.yaml") , 'r', encoding='utf-8') as file:
        # 加载JSON数据
        config = json.load(file)
        try:
            system = db.query(SystemDataModel).filter_by(id=SYSTEM_ID).first()
            if system:
                system.version = config["smart_system"].get("version")
            else:
                system = SystemDataModel(id=SYSTEM_ID, version=config["smart_system"].get("version"), title=config["smart_system"].get("title"), desc=config["smart_system"].get("desc"), machine_id=get_machine_id())
                db.add(system)
            db.commit()
        except Exception as e:
            print(e)
            db.rollback()
app/task/sync_resources.py
File was deleted
app/task/sync_system.py
New file
@@ -0,0 +1,68 @@
import asyncio
import base64
import json
import os
from datetime import datetime
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import hashes
from app.config.const import SYSTEM_ID, SYSTEM_STATUS_EXPIRED, SYSTEM_STATUS_ON, APP_SERVICE_PATH
from app.models import SystemDataModel
from app.models.base_model import SessionLocal
from app.utils.common import get_machine_id
async def sync_system_license():
    print("-------------------------------------------")
    db = SessionLocal()
    try:
        system = db.query(SystemDataModel).filter_by(id=SYSTEM_ID).first()
        if not system:
            return
        machine_id = get_machine_id()
        if system.machine_id:
            if system.machine_id != machine_id:
                system.machine_id = machine_id
                if system.status == SYSTEM_STATUS_ON:
                    system.status = SYSTEM_STATUS_EXPIRED
            else:
                if system.status == SYSTEM_STATUS_ON:
                    if not system.license_code or system.expired_at < datetime.now():
                        system.status = SYSTEM_STATUS_EXPIRED
                    else:
                        try:
                            with open(os.path.join(APP_SERVICE_PATH, "pom/public_key.pem"), "rb") as f:
                                public_key = serialization.load_pem_public_key(f.read())
                            license_data, signature = base64.b64decode(system.license_code).split(b"-----", 1)
                            # print(license_data)
                            public_key.verify(
                                signature,
                                license_data,
                                padding.PSS(
                                    mgf=padding.MGF1(hashes.SHA256()),
                                    salt_length=padding.PSS.MAX_LENGTH
                                ),
                                hashes.SHA256()
                            )
                            license_dict = json.loads(license_data.decode('utf-8'))
                            # print(license_dict)
                            expiration_date = datetime.fromisoformat(license_dict['expiration_date'])
                            system.expired_at = expiration_date
                            if expiration_date < datetime.now():
                                system.status = SYSTEM_STATUS_EXPIRED
                        except Exception as e:
                            print(e)
                            system.status = SYSTEM_STATUS_EXPIRED
        else:
            if system.status == SYSTEM_STATUS_ON:
                system.status = SYSTEM_STATUS_EXPIRED
        db.commit()
    except Exception as e:
        print(e)
    finally:
        db.close()
def sync_resource():
    asyncio.run(sync_system_license())
app/utils/common.py
@@ -1,6 +1,31 @@
import pytz
import platform
import subprocess
from datetime import datetime
def current_time():
    tz = pytz.timezone('Asia/Shanghai')
    return datetime.now(tz)
def get_machine_id():
    """获取机器的唯一标识"""
    if platform.system() == "Windows":
        # Windows 系统
        command = "wmic csproduct get UUID"
        process = subprocess.Popen(command.split(), stdout=subprocess.PIPE)
        output, _ = process.communicate()
        machine_id = output.decode().strip().split("\n")[1].strip()
    elif platform.system() == "Darwin":
        # macOS 系统
        command = "system_profiler SPHardwareDataType | grep 'Hardware UUID' | awk '{print $4}'"
        process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
        output, _ = process.communicate()
        machine_id = output.decode().strip()
    else:
        # Linux 系统
        machine_id = open("/etc/machine-id").read().strip()
    # print(machine_id)
    return machine_id
main.py
@@ -27,6 +27,7 @@
    sync_resources_from_json
from app.init_config.init_run_data import sync_default_data
from app.task.sync_account_token import start_sync_token_task
from app.task.sync_system import sync_resource
init_db()
@@ -56,6 +57,7 @@
scheduler = BackgroundScheduler()
scheduler.add_job(sync_agents_v2, 'interval', minutes=60, id="sync_resource_data")
scheduler.add_job(start_sync_token_task, 'interval', minutes=5, id="sync_token_1")
scheduler.add_job(sync_resource, 'interval', minutes=5, id="sync_resource_1")
scheduler.start()