- 企业应用
- 后端
【免费下载链接】dolibarr
Dolibarr ERP CRM is a modern software package to manage your company or foundation's activity (contacts, suppliers, invoices, orders, stocks, agenda, accounting, ...). it's an open source Web application (written in PHP) designed for businesses of any sizes, foundations and freelancers.
Web Portal(网络门户)是 Dolibarr ERP/CRM 内置的一个模块,用于为你的客户、供应商、合作伙伴或会员提供一个开箱即用的自助门户:这些外部人员无需进入后台(backoffice),就能在独立域名上查看甚至修改与自己相关的业务数据。读完本文,你将掌握 Web Portal 模块的启用与配置流程、门户账号(Website account)的创建方法、按业务模块开放数据权限的完整配置项,以及它基于控制器(Controller)驱动的内部运行原理,能够直接在自己的 Dolibarr 实例上落地一套客户自助门户。
模块定位:它解决什么问题
按照 htdocs/webportal/README.md 的说明,Web Portal 是一个"开箱即用"(ready to use)的门户模块,服务对象是:
- 客户(customers)
- 供应商(suppliers)
- 合作伙伴(partners)
- 会员模块(Membership)下的会员(members)
它的核心价值是解耦前台与后台:门户的访问账号(登录名和密码)可以为任意第三方(thirdparty)创建,入口位于第三方卡片上的"Web site accounts"(网站账号)标签页。README 特别强调,最好为门户配置一个独立的 Web 服务器、独立的虚拟主机(virtual host)和独立域名,这样外部用户访问门户时,不会暴露你后台(backoffice)安装的域名和 URL,从部署层面把门户与内部管理系统隔离。
在模块描述文件 htdocs/core/modules/modWebPortal.class.php 中可以看到它的注册信息:模块编号numero = 11000,权限类名rights_class = 'webportal',所属功能族family = "portal",语言文件使用website,并在启用时创建数据目录/webportal/temp。模块提供的唯一权限是"Administer users of the customer/partner webportal module"(管理客户/合作伙伴门户模块的用户),权限类型为write。
启用模块与门户入口
启用模块
Web Portal 是一个标准内置模块,启用方式与 Dolibarr 其他模块一致:
- 以管理员身份登录后台,进入Home → Setup → Modules(模块列表);
- 找到Web Portal模块并启用;
- 启用后,模块在数据库中写入
MAIN_MODULE_WEBPORTAL常量标记,并在conf中挂载$conf->webportal配置对象(见 modWebPortal.class.php 构造器)。
门户入口地址
门户的公开入口固定为后台目录下的public/webportal/index.php。在 htdocs/webportal/admin/setup.php 中可以看到该入口 URL 的生成逻辑:它使用$urlwithroot.'/public/webportal/index.php'拼接,并追加?entity=xxx参数(当启用多公司 multicompany 时),实际地址形如:
https://your-domain/htdocs/public/webportal/index.php而入口文件 htdocs/public/webportal/index.php 本身非常简洁:它先引入webportal.main.inc.php完成 Dolibarr 环境与Context的初始化,然后调用$context->controllerInstance->action()处理动作,再调用$context->controllerInstance->display()渲染页面——所有逻辑都委托给当前选中的控制器(Controller)。
门户账号(Website Account)体系
账号来源
README 明确指出:门户访问账号可以为任意第三方创建。在 Dolibarr 中,这类账号的数据模型是societe_account表(由 htdocs/societe/class/societeaccount.class.php 封装),其对象类名为WebsiteAccount(见 htdocs/societe/website.php 中$objectclass = 'WebsiteAccount')。
管理入口位于第三方的Web site accounts标签页(htdocs/societe/website.php),页面标题为 "Website Accounts",支持批量列表、排序、搜索与新建;新建按钮会跳转到website/websiteaccount_card.php?action=create&fk_soc=第三方ID创建账号。
账号如何被门户认证
登录认证的底层实现在 htdocs/webportal/class/context.class.php:
getThirdPartyAccountFromLogin($login, $pass):从societe_account表中按登录名查询,且限定site = 'dolibarr_portal'(说明门户账号在网站账号体系中用dolibarr_portal这个站点标识与普通网站账号区分)、status = 1(启用状态),再通过dol_verifyHash($pass, $pass_crypted, '0')校验密码哈希;getMemberAccountFromLogin($login, $pass):从adherent(会员)表中按登录名查询启用状态会员并校验密码哈希;- 登录状态通过 Session 保存:
$_SESSION["webportal_logged_thirdparty_account_id"](第三方账号)或$_SESSION["webportal_logged_member_account_id"](会员账号),userIsLog()据此判断用户是否已登录(见 context.class.php)。
值得注意的是,认证代码中包含防暴力破解逻辑:当密码错误时,代码会sleep(1)延时 1 秒,与"登录名无效"时的延迟保持一致,避免攻击者通过响应时间差异枚举有效账号。同时,错误码体系为:-1数据库查询失败、-2找到多个账号(数据异常)、-3密码错误。
会员账号的特殊性
README 特别说明,会员(Membership)登录走的是会员账号体系(adherent表),而不是societe_account。也就是说:
- 第三方(客户/供应商/合作伙伴)→ 使用Web site accounts标签页创建的
societe_account账号; - 会员 → 使用会员自身的登录账号(
adherent.login/adherent.pass_crypted)。
门户对外暴露的数据能力(按模块划分)
README 给出了门户可读/可修改数据的完整清单。关键在于:每一项能力都依赖于对应业务模块是否已启用。整理如下:
| 已启用的业务模块 | 门户可访问的数据 | 读写能力 |
|---|---|---|
| Thirdparty(第三方) | 第三方的名称、电话、邮箱、地址 | 读 + 修改 |
| Partnership(合作伙伴关系) | 合作伙伴关系的属性(状态、开始日期、结束日期) | 读 |
| Proposal(报价单) | 自己的报价单 | 读 |
| Sale Order(销售订单) | 自己的订单 | 读 |
| Invoice(发票) | 自己的发票 | 读 |
| Supplier(供应商模块) | 价格请求、订单、发票 | 读 |
| Membership(会员) | 第三方的名称、电话、邮箱、地址;会员状态(开始/结束日期、已付金额) | 读 + 修改 |
需要留意 README 的一个细节:在 "Proposal(报价单)" 条目下原文写的是 "Read its orders",但从上下文(Proposal 模块)以及源码中WEBPORTAL_PROPAL_LIST_ACCESS常量来看,其实际语义是读取报价单列表——README 此处存在笔误,读者应以"报价单"理解该行。
源码级的对应关系
上述每种数据能力,在 htdocs/webportal/class/ 目录下都有对应的门户业务对象类:
webportalpropal.class.php—— 报价单webportalorder.class.php—— 订单webportalinvoice.class.php—— 发票webportalpartnership.class.php—— 合作伙伴关系webportalmember.class.php—— 会员webportalficheinter.class.php—— interventions(工单/服务干预)webportalticket.class.php—— 工单/服务单webportalfieldsmanager.class.php—— 门户字段管理器(控制哪些字段在门户中可见/可编辑)
同时,htdocs/webportal/controllers/ 目录下的控制器与之一一对应:propallist、orderlist、invoicelist、ficheinterlist、ticketlist(各类列表)、membercard、partnershipcard(卡片详情)、documentlist/shareddocuments(共享文档/GED 文档)、viewimage(图片查看)等。这些控制器的注册位于 context.class.php 的initController()方法中,控制器名通过 URL 参数controller(仅允许aZ09字符,做了输入白名单过滤)传入,默认控制器为default。
门户后台配置详解
门户的配置页面集中在htdocs/webportal/admin/下,共三个:
| 页面 | 路径 | 作用 |
|---|---|---|
| 设置(Settings) | htdocs/webportal/admin/setup.php | 核心参数配置 |
| 皮肤与颜色(SkinAndColors) | htdocs/webportal/admin/setup_theme.php | 主题外观 |
| CSS 页面 | htdocs/webportal/admin/configcss.php | 自定义 CSS |
这些标签页的组装逻辑见 htdocs/webportal/lib/webportal.lib.php 的webportalAdminPrepareHead()。配置页仅管理员可访问(if (!$user->admin) accessforbidden();)。
核心配置参数
从 setup.php 的源码可以看到门户的核心配置项(以 Dolibarr 常量形式存储):
| 常量名 | 类型/控件 | 说明 |
|---|---|---|
WEBPORTAL_USER_LOGGED | 用户选择器 | 指定用于门户的 Dolibarr 内部用户(下拉选择启用用户),用于门户会话绑定 |
WEBPORTAL_ROOT_URL | 文本框 | 门户根 URL(占位符提示https://)。Context::getRootConfigUrl()会优先读取它,未配置时回退到/public/webportal/的公开路径(见 context.class.php) |
WEBPORTAL_TITLE | 文本框 | 门户标题,默认值取MAIN_INFO_SOCIETE_NOM(公司名称) |
WEBPORTAL_PROPAL_LIST_ACCESS | 是/否 | 是否开放报价单列表(仅当 propal 模块启用时出现) |
WEBPORTAL_ORDER_LIST_ACCESS | 是/否 | 是否开放订单列表(仅当 order 模块启用时出现) |
WEBPORTAL_INVOICE_LIST_ACCESS | 是/否 | 是否开放发票列表(仅当 invoice 模块启用时出现) |
WEBPORTAL_FICHEINTER_LIST_ACCESS | 是/否 | 是否开放 interventions 列表(仅当 intervention 模块启用时出现) |
WEBPORTAL_TICKET_LIST_ACCESS | 是/否 | 是否开放工单列表(仅当 ticket 模块启用时出现) |
WEBPORTAL_PARTNERSHIP_CARD_ACCESS | 下拉选择 | 合作伙伴关系卡片访问级别:hidden(隐藏)/visible(可见),仅当 partnership 模块启用时出现 |
WEBPORTAL_MEMBER_CARD_ACCESS | 下拉选择 | 会员卡片访问级别:hidden(隐藏)/visible(可见)/edit(可编辑),仅当 member 模块启用时出现 |
由此可以总结出门户权限模型的两条核心规律:
- 模块前置:配置项是否出现,取决于对应业务模块是否启用(
isModEnabled('propal')、isModEnabled('order')等)。README 中"如果 X 模块已启用"的条件与此完全一致; - 细粒度开关:列表类功能用简单的"是/否"开关控制,而涉及敏感信息(会员、合作伙伴关系)的卡片类功能提供
hidden / visible / edit三级访问级别,其中"可编辑"级别直接对应 README 中"Read/modify"的修改能力。
关于 URL 与部署的补充配置
除了上述可见配置项,源码中还引用了一个隐藏配置WEBPORTAL_CDN_URL:用于为/public/includes/的静态资源设置 CDN 地址,避免门户页面直接暴露后台资源 URL(见 context.class.php 构造器中的getDolGlobalString('WEBPORTAL_CDN_URL', dol_buildpath('/public/includes/', 3)))。这与 README 强调的"隐藏后台域名"理念一脉相承,属于对公开 URL 的进一步保护手段。
门户运行机制:控制器驱动架构
从代码结构可以推断,Web Portal 采用了一套轻量级 MVC(Model-View-Controller)架构,这是它与 Dolibarr 传统页面(直接混排 HTML 的 PHP 脚本)最明显的差异:
public/webportal/index.php │ ▼ Context::getInstance()(单例) │ ├── 根据 ?controller=xxx 参数加载控制器(白名单 aZ09) ├── $controllerInstance->action() // 业务动作,发生在 HTML 输出前 └── $controllerInstance->display() // 渲染视图关键组成部分:
- 入口:htdocs/public/webportal/index.php——全部逻辑委托给控制器;
- 上下文(Context):htdocs/webportal/class/context.class.php——单例,持有数据库连接、当前控制器、登录用户/第三方/会员、主题、根 URL、token、错误与事件消息栈等全局状态。控制器定义通过
addControllerDefinition()注册,controller参数经GETPOST('controller', 'aZ09')白名单过滤; - 控制器基类:htdocs/webportal/class/controller.class.php——定义了
checkAccess()、action()、display()的标准生命周期; - 具体控制器:htdocs/webportal/controllers/——如
LoginController(未登录时显示登录页)、DefaultController(门户首页)、PropalListController、OrderListController、InvoiceListController、MemberCardController、PartnershipCardController等; - 视图模板:
/public/webportal/tpl/目录(Context通过realpath(__DIR__ . '/../../public/webportal/tpl')定位),由loadTemplate()加载,如header_login、login、footer等模板; - 主题系统:htdocs/webportal/class/webPortalTheme.class.php——门户拥有独立的主题渲染层(
WebPortalTheme),配合setup_theme.php与configcss.php提供皮肤和自定义 CSS 能力。
登录流程
以 login.controller.class.php 为例,可以还原完整登录链路:
- 未登录用户访问门户 →
Context根据请求参数选中控制器; LoginController::checkAccess()调用Context::userIsLog():若 Session 中已存在webportal_logged_thirdparty_account_id或webportal_logged_member_account_id,返回true(已登录,跳转离开登录页),否则放行显示登录页;action()设置页面标题WebPortalHomeTitle/ 描述WebPortalHomeDesc;display()加载header_login、login、footer模板渲染登录表单;- 提交登录表单后,
Context::getThirdPartyAccountFromLogin()/getMemberAccountFromLogin()完成认证并写入 Session。
整个过程体现了安全设计的几个要点:控制器参数白名单、密码哈希校验(dol_verifyHash)、登录失败延时防爆破、Session 隔离的登录状态。
部署建议与最佳实践
结合 README 与源码,落地 Web Portal 时建议遵循以下实践:
- 独立域名 + 独立虚拟主机:README 明确建议为门户配置独立 Web 服务器、虚拟主机和域名,避免门户 URL 泄露后台地址。生产环境中应在 Web 服务器层配置 HTTPS;
- 配置
WEBPORTAL_ROOT_URL:在门户设置页填写门户对外根 URL;若使用 CDN,可额外配置隐藏常量WEBPORTAL_CDN_URL隐藏静态资源真实地址; - 按需开放数据:只启用你确实需要暴露的业务模块访问开关(报价单/订单/发票/工单等),会员与合作伙伴卡片按
hidden / visible / edit三档控制,做到最小权限开放; - 账号管理:第三方账号统一在第三方卡片的Web site accounts标签页创建(
societe_account表,站点标识dolibarr_portal);会员则使用会员自身的登录账号体系,二者认证路径不同,需分别管理; - 了解版本前提:模块要求 PHP 7.0 及以上(见 modWebPortal.class.php 的
phpmin),并依赖相应业务模块(Thirdparty、Proposal、Order、Invoice、Supplier、Partnership、Membership 等)启用后才开放对应数据能力。
进一步阅读
- 模块官方文档入口见 htdocs/webportal/README.md(文档尾部指向 Dolibarr Wiki 的 Module Web Portal 页面);
- 模块描述与启用细节:htdocs/core/modules/modWebPortal.class.php;
- 门户配置页面:htdocs/webportal/admin/setup.php;
- 门户运行核心(Context/认证/控制器注册):htdocs/webportal/class/context.class.php;
- 门户业务对象类:htdocs/webportal/class/;
- 门户控制器:htdocs/webportal/controllers/;
- 门户公开入口:htdocs/public/webportal/index.php;
- 网站账号管理页面:htdocs/societe/website.php。
- 企业应用
- 后端
【免费下载链接】dolibarr
Dolibarr ERP CRM is a modern software package to manage your company or foundation's activity (contacts, suppliers, invoices, orders, stocks, agenda, accounting, ...). it's an open source Web application (written in PHP) designed for businesses of any sizes, foundations and freelancers.
相关推荐
为什么Lossless Claw的压缩从不失败?深度拆解阈值触发与摘要三级降级回退机制
为什么Lossless Claw的压缩从不失败?深度拆解阈值触发与摘要三级降级回退机制 Lossless Claw(LCM,Lossless Context M
Unkey Portal 前端架构指南:面向客户的门户应用分层设计与会话管理
Unkey Portal 前端架构指南:面向客户的门户应用分层设计与会话管理 Portal 是 Unkey 面向最终客户的官方门户应用——Unkey 客户的终端
后端API网关认证鉴权Midscene免费教程:自然语言完成浏览器、Android与iOS自动化,2步启动
Midscene免费教程:自然语言完成浏览器、Android与iOS自动化,2步启动 Midscene 是一个开源的 AI 浏览器自动化工具:你用自然语言描述任
人工智能AI Agent测试GUI 自动化浏览器控制测试智能体
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考