Dify智能体平台源码二次开发笔记(4) - 多租户的SAAS版实现

news2025/5/10 0:42:09

前言

        Dify 的多租户功能是其商业版的标准功能,我们应当尊重其盈利模式。只有保持良性的商业运作,Dify 才能持续发展,并为用户提供更优质的功能。因此,此功能仅限学习使用。
我们的需求是:实现类似 SaaS 版的账号隔离,包括智能体、知识库、插件和模型配置等模块的完全隔离。为此,需要启用多租户功能。

租户创建

添加controller

首先创建api的调用,这个controller代码,我就创建在controllers/console/auth下面,起名:tenant.py

class TenantCreateApi(Resource):
    """Resource for creating a new tenant."""

    @validate_token
    def post(self):
        """Create a new tenant."""
        parser = reqparse.RequestParser()
        parser.add_argument("name", type=str, required=True, location="json")
        args = parser.parse_args()
        # if not FeatureService.get_system_features().is_allow_create_workspace:
        #     raise NotAllowedCreateWorkspace()

        tenant = TenantService.create_tenant(args["name"])

        return {"result": "success", "data": {"tenant_id": str(tenant.id)}}

这里方法很简单,接收一个租户名称,通过调用

TenantService的租户创建方法,把租户创建成功。

这里@validate_token,是我自己集成我自己云中来平台登录验证的装饰器,因为我是放在我云中来平台调用的,不想用dify的登录验证,如果大家需要用dify的登录验证,然后在代码里需要使用

account = current_user这个登录用户来做业务处理,就可以换成:
@setup_required
@login_required
@account_initialization_required.

这三个装饰器,也是没有登录问题的。

配置路由
api.add_resource(TenantCreateApi, "/tenant/create")
import

我是创建在console下面的,记得在__init__.py里,把tenant import 加上

from .auth import activate, data_source_bearer_auth, data_source_oauth, forgot_password, login, oauth , tenant
集成三方系统调用
def validate_token(view: Optional[Callable] = None, *, fetch_user_arg: Optional[FetchUserArg] = None):
    def decorator(view_func):
        @wraps(view_func)
        def decorated_view(*args, **kwargs):
            auth_header = request.headers.get("Authorization")
            if auth_header is None or " " not in auth_header:
                raise Unauthorized("Authorization不通过!!!")
            auth_scheme, auth_info = auth_header.split(None, 1)
            auth_scheme = auth_scheme.lower()
            if auth_scheme != "bearer":
                raise Unauthorized("Authorization不通过!")
            if not jolywood_redis_client.exists("authorization:token:" + auth_info):
                raise Unauthorized("请登录云中来!!")
            return view_func(*args, **kwargs)

        return decorated_view

    if view is None:
        return decorator
    else:
        return decorator(view)

这个比较简单,验证我自己云中来平台的登录token

添加Service

因为dify本身就有

TenantService这个类了,我们就不要再去创建其它的服务类。直接在类中添加我们需要的方法。
@staticmethod
    def create_tenant(name: str, is_setup: Optional[bool] = False, is_from_dashboard: Optional[bool] = False) -> Tenant:
        """Create tenant"""
        # if (
        #     not FeatureService.get_system_features().is_allow_create_workspace
        #     and not is_setup
        #     and not is_from_dashboard
        # ):
        #     from controllers.console.error import NotAllowedCreateWorkspace
        #
        #     raise NotAllowedCreateWorkspace()
        tenant = Tenant(name=name)

        db.session.add(tenant)
        db.session.commit()

        tenant.encrypt_public_key = generate_key_pair(tenant.id)
        db.session.commit()
        return tenant

几行代码轻松搞定,dify这里已经写好了密钥的生成方法generate_key_pair,拿来用就行。

结果验证

通过postman的测是调用,租户创建成功

同时我minio中的租户密钥也创建成功

租户查询

和创建一样分成controller和service层的实现

class TenantAllListApi(Resource):
    @validate_token
    def get(self):
        parser = reqparse.RequestParser()
        parser.add_argument("page", type=int, required=False, default=1, location="args")
        parser.add_argument("limit", type=int, required=False, default=20, location="args")
        parser.add_argument("search", type=str, required=False, location="args")
        args = parser.parse_args()
        tenants = TenantService.get_all_tenants()
        tenant_list = [{
            "id": str(tenant.id),
            "name": tenant.name,
            "created_at": tenant.created_at.isoformat()
        } for tenant in tenants]
        return {"result": "success", "data": tenant_list}
@staticmethod
    def get_all_tenants() -> list[Tenant]:
        """Get account join tenants"""
        return (
            db.session.query(Tenant).all()
        )

这里写的比较简单,没有分页和查询参数,直接把所有租户显示出来

最后

除了创建、查询,接下来更新和删除我就写了,基本大致相差不大。创建完了租户,接下来就是对用户表和用户租户关联表tenant_account_joins的处理,这个下次再说吧。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2335475.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

layui中transfer两个table展示不同的数据列

在项目的任务开发中需要达到transfer右侧table需要有下拉框可选择状态,左侧table不变 使用的layui版本为2.4.5,该版本没有对transfer可自定义数据列的配置,所以改动transfer.js中的源码 以下为transfer.js部分源码 也是transfer.js去render的…

【机器学习】机器学习笔记

1 机器学习定义 计算机程序从经验E中学习,解决某一任务T,进行某一性能P,通过P测定在T上的表现因经验E而提高。 eg:跳棋程序 E: 程序自身下的上万盘棋局 T: 下跳棋 P: 与新对手下跳棋时赢的概率…

STM32 BOOT设置,bootloader,死锁使用方法

目录 BOOT0 BOOT1的配置含义 bootloader使用方法 芯片死锁解决方法开发调试过程中,由于某种原因导致内部Flash锁死,无法连接SWD以及JTAG调试,无法读到设备,可以通过修改BOOT模式重新刷写代码。修改为BOOT01,BOOT10…

【Redis】string类型

目录 1、介绍2、底层实现【1】SDS【2】int编码【3】embstr编码【4】raw编码【5】embstr和raw的区别 3、常用指令【1】字符串基本操作:【2】批量操作【3】计数器【4】过期时间【5】不存在就插入 4、使用场景 1、介绍 string是redis中最简单的键值对形式,…

PostgreSQL全平台安装指南:从入门到生产环境部署

一、PostgreSQL核心特性全景解析 1.1 技术架构深度剖析 graph TDA[客户端] --> B(连接池)B --> C{查询解析器}C --> D[优化器]D --> E[执行引擎]E --> F[存储引擎]F --> G[物理存储]G --> H[WAL日志]H --> I[备份恢复] 1.2 特性优势对比矩阵 特性维度…

UE5 物理模拟 与 触发检测

文章目录 碰撞条件开启模拟关闭模拟 多层级的MeshUE的BUG 触发触发条件 碰撞 条件 1必须有网格体组件 2网格体组件必须有网格,没有网格虽然可以开启物理模拟,但是不会有任何效果 注意开启的模拟的网格体组件会计算自己和所有子网格的mesh范围 3只有网格…

做仪器UI用到的颜色工具网站

https://color.adobe.com/zh/create/color-wheel 1. 图片取颜色工具 2. 对比度工具,煤矿井下设备,光线暗,要求背景与文字有合适的对比度,可以用这个软件 3. 颜色生成ARGB的值工具,这三个工具,都在上面这…

网络安全·第三天·ICMP协议安全分析

一、ICMP功能介绍 ICMP(Internet Control Message Protocal)是一种差错和控制报文协议,不仅用于传输差错报文, 还传输控制报文,但是ICMP只是尽可能交付,提供的服务是无连接、不可靠的,并不能保…

SpringBoot对接火山引擎大模型api实现图片识别与分析

文章目录 一、前言二、创建应用三、后端1.SDK集成2.调用Rest API 四、前端 一、前言 Spring AI实战初体验——实现可切换模型AI聊天助手-CSDN博客 如上,在上一篇博客,我们已经实现了spring ai对接本地大模型实现了聊天机器人,但是目前有个新…

单片机方案开发 代写程序/烧录芯片 九齐/应广等 电动玩具 小家电 语音开发

在电子产品设计中,单片机(MCU)无疑是最重要的组成部分之一。无论是消费电子、智能家居、工业控制,还是可穿戴设备,小家电等,单片机的应用无处不在。 单片机,简而言之,就是将计算机…

ARCGIS PRO 在已建工程地图中添加在线地图

一、手工添加 如图所示: 1、在上方的菜单栏中点击“插入”,选择“连接” 2、新建ArcGIS Server 3、在弹出框中输入在线图集的URL,点击“确定” https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer 4、查看在…

ScholarCopilot:“学术副驾驶“

这里写目录标题 引言:学术写作的痛点与 AI 的曙光ScholarCopilot 的核心武器库:智能生成与精准引用智能文本生成:不止于“下一句”智能引用管理:让引用恰到好处 揭秘背后机制:检索与生成的动态协同快速上手&#xff1a…

MATLAB仿真多相滤波抽取与插值的频谱变化(可视化混叠和镜像)

MATLAB画图仿真多相滤波抽取与插值的频谱变化 可视化多速率信号处理抽取与插值的频谱变化 实信号/复信号 可视化混叠和镜像 目录 前言 一、抽取的基本原理 二、MATLAB仿真抽取运算 三、内插的基本原理 四、MATLAB仿真内插运算 总结 前言 在多速率系统中增加信号采样率的运…

MySQL-存储引擎索引

存储引擎 MySQL体系结构 1). 连接层 最上层是一些客户端和链接服务,包含本地sock 通信和大多数基于客户端/服务端工具实现的类似于 TCP/IP的通信。主要完成一些类似于连接处理、授权认证、及相关的安全方案。在该层上引入了线程 池的概念,为通过认证安…

图像处理有哪些核心技术?技术发展现状如何?

在数字化信息爆炸的时代,文档图像预处理技术正悄然改变着我们处理文字信息的方式。无论是手持拍摄的收据、扫描仪中的身份证,还是工业机器人采集的复杂文档,预处理技术都在背后默默提升着OCR(光学字符识别)系统的性能。…

【小沐学GIS】基于C++绘制三维数字地球Earth(QT5、OpenGL、GIS、卫星)第五期

🍺三维数字地球系列相关文章如下🍺:1【小沐学GIS】基于C绘制三维数字地球Earth(OpenGL、glfw、glut)第一期2【小沐学GIS】基于C绘制三维数字地球Earth(OpenGL、glfw、glut)第二期3【小沐学GIS】…

spring cloud OpenFeign 详解:安装配置、客户端负载均衡、声明式调用原理及代码示例

OpenFeign 详解&#xff1a;安装配置、客户端负载均衡、声明式调用原理及代码示例 1. OpenFeign 安装与配置 (1) 依赖管理 <!-- pom.xml 添加以下依赖 --> <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud…

用 Deepseek 写的uniapp血型遗传查询工具

引言 在现代社会中&#xff0c;了解血型遗传规律对于优生优育、医疗健康等方面都有重要意义。本文将介绍如何使用Uniapp开发一个跨平台的血型遗传查询工具&#xff0c;帮助用户预测孩子可能的血型。 一、血型遗传基础知识 人类的ABO血型系统由三个等位基因决定&#xff1a;I…

【眼底辅助诊断开放平台】项目笔记

这是一个标题 任务一前端页面开发&#xff1a;后端接口配置&#xff1a; 任务二自行部署接入服务 日志修改样式和解析MD文档接入服务 Note前端登陆不进去/更改后端api接口304 Not Modifiedlogin.cache.jsonERR_CONNECTION_TIMED_OUT跨域一般提交格式proxy.ts src/coponents 目录…

Java笔记5——面向对象(下)

目录 一、抽象类和接口 1-1、抽象类&#xff08;包含抽象方法的类&#xff09; 1-2、接口 ​编辑​编辑 二、多态 ​编辑 1. 自动类型转换&#xff08;向上转型&#xff09; 示例&#xff1a; 注意&#xff1a; 2. 强制类型转换&#xff08;向下转型&#xff09; 示…