☰
CRMEB 对外 API(outapi)详解:基于 Tp6 的第三方开放接口设计实践
2026/10/14 7:28:21 网站建设 项目流程
  • 后端
  • 电商
  • 前端

【免费下载链接】CRMEB

🔥CRMEB开源商城免费开源多语言商城系统,Tp6框架商城,系统可商用;包含小程序商城、H5商城、公众号商城、PC商城、App,支持分销、拼团、砍价、秒杀、优惠券、积分、会员等级、小程序直播、页面DIY,前后端分离,方便二开,更有详细使用文档、接口文档、数据字典、二开文档/视频教程,欢迎大家提出宝贵意见和建议

项目地址:https://gitcode.com/gh_mirrors/cr/CRMEB
点击查看免费下载

本文聚焦 CRMEB 开源商城(ThinkPHP 6 架构)中的 crmeb/app/outapi 应用目录,系统讲解项目如何通过独立的应用分层,为合作第三方开放不依赖登录态的 RESTful 接口,覆盖目录设计、JWT 鉴权、路由组织、账号权限、接口能力清单与异常处理。读完本文,你将掌握在 CRMEB 项目中接入第三方小程序/APP、同步订单、下发商品与库存的完整实现方案,并能够对照源码定位关键调用链。

outapi 是什么:对外部开放的 API 定义目录

在 CRMEB 的多应用结构中,outapi是一个独立的应用目录,专门用于定义项目对外开放的接口。它承担的角色可以概括为三点:

  • 是项目对合作第三方开放的 API 接口定义目录;
  • 这里的接口可以被第三方直接调用来获取数据或完成相关业务;
  • 这类接口与项目内部使用的 API(如adminapi、api、kefuapi)在定位上有明确区隔。

目录入口说明位于 crmeb/app/outapi/README.md,它明确给出了这类 API 与内部 API 的三个关键区别:

  1. 对外开放,不需要登录授权:第三方无需注册平台用户、无需携带用户会话,而是通过专门的账号体系(appid/appsecret)换取访问令牌;
  2. 安全限制较严,只提供必要接口:不会把内部全部能力暴露出去,只开放合作方业务所需的必要端点;
  3. 接口规范遵循 RESTful 原则:以资源为中心组织 URL,使用 GET/POST/PUT/DELETE 表达查询、创建、修改、删除语义。

常见接入场景

README 中列举了三个最典型的场景,也是本文后续接口能力章节的对应落点:

  • 第三方小程序/APP 直接获取商品数据——对应product/list、product/:id、category/list等商品与分类接口;
  • 第三方商户后台系统同步订单信息——对应order/list、order/:order_id、order/delivery/:order_id、refund/list等订单与售后接口;
  • 小程序支付回调通知类接口——对应账号配置中可自定义的推送接口(订单创建、支付、售后等事件推送)。

为什么要单独用这个目录

将外部接口独立成目录,可以带来三方面收益(对应 README 的表述):

  • 实现与其他系统的深度集成:通过标准 HTTP API 对接 ERP、分销系统、外部商城或自研 APP;
  • 让更多场景能够使用 CRMEB 提供的能力:把商城沉淀的商品、订单、用户、优惠券能力复用给更多端;
  • 降低对第三方的侵入性,仅开放必要接口:通过账号 + 接口权限(rules)按需授权,避免把整个后台能力暴露出去。

目录结构与代码分层

outapi遵循 CRMEB 一贯的 Controller / Middleware / Validate / Route 分层风格,同时复用app/services中的业务服务层:

crmeb/app/outapi/ ├── config/route.php # 本应用路由配置 ├── controller/ │ ├── AuthController.php # 对外接口控制器基类(解析 outId / outInfo / auth) │ ├── Login.php # 登录:获取 token / 刷新 token │ ├── StoreCategory.php # 商品分类 │ ├── StoreProduct.php # 商品 │ ├── StoreOrder.php # 订单 │ ├── RefundOrder.php # 售后/退款 │ ├── StoreCoupon.php # 优惠券 │ ├── User.php # 用户 │ └── UserLevel.php # 用户等级 ├── middleware/ │ └── AuthTokenMiddleware.php # 对外接口鉴权中间件 ├── route/route.php # 对外路由定义 ├── validate/ │ ├── LoginValidate.php # 登录参数校验 │ ├── StoreCategoryValidate.php # 分类参数校验 │ └── StoreOutAccountValidate.php # 后台账号参数校验 ├── OutApiExceptionHandle.php # 本应用异常处理 └── provider.php # 覆盖全局异常 Handle

业务逻辑并不直接写在控制器里,而是委托给app/services/out与各业务域的Out*Services:

  • crmeb/app/services/out/OutAccountServices.php:对外账号的登录、token 解析、刷新、推送配置;
  • crmeb/app/services/out/OutInterfaceServices.php:对外接口权限校验与接口文档管理;
  • 业务服务如 OutStoreOrderServices.php、OutStoreProductServices.php、OutStoreOrderRefundServices、OutUserServices等,负责订单、商品、售后、用户的查询与写操作。

数据访问层则复用 crmeb/app/dao/out/OutAccountDao.php 与OutInterfaceDao,最终落到eb_out_account、eb_out_interface两张表(建表语句见 crmeb/public/install/crmeb.sql)。

认证体系:appid/appsecret 换取 JWT

对外接口虽然“不需要登录授权”,但并不意味着裸奔——它使用一套独立的账号 + 令牌体系。

获取 access_token

第三方接入的第一步是通过POST /access_token用appid与appsecret换取令牌,路由定义在 crmeb/app/outapi/route/route.php:

//获取token Route::post('access_token', 'Login/getToken')->name('getToken')->option(['real_name' => '登录获取token']); //刷新token Route::post('refresh_token', 'Login/refreshToken')->name('refreshToken')->option(['real_name' => '刷新token']);

控制器实现见 crmeb/app/outapi/controller/Login.php,它先通过LoginValidate校验参数(appid必须为 4~30 位字母数字,规则定义在 LoginValidate.php),再调用OutAccountServices::authLogin()。

底层authLogin的逻辑(见 OutAccountServices.php)依次完成:

  1. 按appid查询未删除的对外账号,不存在则抛AuthException(410141);
  2. 使用password_verify校验appsecret(后台创建账号时用password_hash($data['appsecret'], PASSWORD_DEFAULT)加密存储,见 SystemOutAccount.php);
  3. 检查账号状态status == 0时禁止登录;
  4. 通过createToken($autInfo->id, 'out')生成 JWT(type 固定为out);
  5. 记录last_time与ip;
  6. 返回access_token、exp_time以及隐藏敏感字段后的auth_info。

请求与返回示例(来源为 crmeb.sql 中预置的接口文档数据eb_out_interfaceid=2):

{ "appid": "demo", "appsecret": "XXWaCnCZi8b6jcSWzkBcbCKKpkpNPrKy" }
{ "status": 200, "msg": "获取成功", "data": { "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...", "exp_time": 1655954673, "auth_info": { "id": 7, "appid": "demo", "title": "测试账号" } } }

token 刷新

令牌过期前可调用POST /refresh_token,传入旧的access_token换新。OutAccountServices::refresh()(见 OutAccountServices.php)会先完成verifyToken校验,然后删除缓存中的旧 token 并签发新 token,实现“平滑续期”。

中间件统一鉴权

除access_token、refresh_token之外的对外接口,路由组统一挂在AuthTokenMiddleware之下(见 route.php)。中间件核心逻辑见 AuthTokenMiddleware.php:

  1. 从请求头Authori-zation中取出Bearer前缀后的 token(header 名称来自Config::get('cookie.token_name', 'Authori-zation'));
  2. 调用OutAccountServices::parseToken($token)解析并校验;
  3. 通过$request->macro('outId')、$request->macro('outInfo')将账号信息注入请求对象,供控制器基类使用;
  4. 调用OutInterfaceServices::verifyAuth($request)做接口权限校验(详见下文)。

parseToken的校验链路(见 OutAccountServices.php)包括:token 是否为空/为undefined、缓存中是否存在该 token(md5Token维度)、JWT 能否解析出id且type == 'out'、JWT 签名与有效期是否合法(通过jwtAuth->verifyToken()),以及账号是否存在、是否被禁用(status == 2时拒绝,见checkAuth)。任何一环失败都会抛出对应错误码的AuthException。

控制器基类 AuthController.php 在initialize()中统一读取outId、outInfo与账号授权规则auth,后续业务控制器可据此感知“当前是哪个第三方账号在调用”。

路由设计:RESTful 接口能力清单

对外路由全部定义在 crmeb/app/outapi/route/route.php,分为公共接口(无需鉴权)与业务接口(需鉴权)两组,业务接口按资源划分为以下能力域:

商品分类(mark: category)

方法路径控制器动作说明
GETcategory/listStoreCategory/index分类列表
GETcategory/:idStoreCategory/read获取分类
POSTcategoryStoreCategory/save新增分类
PUTcategory/:idStoreCategory/update修改分类
DELETEcategory/:idStoreCategory/delete删除分类
PUTcategory/set_show/:id/:is_showStoreCategory/set_show修改分类状态

分类新增/修改支持pid、cate_name、pic、big_pic、sort、is_show字段,并经由 StoreCategoryValidate.php 校验,实现在 StoreCategory.php。

商品(mark: product)

方法路径控制器动作说明
GETproduct/listStoreProduct/index商品列表
POSTproductStoreProduct/save新增商品
PUTproduct/:idStoreProduct/update修改商品
GETproduct/:idStoreProduct/read获取商品
PUTproduct/set_show/:id/:is_showStoreProduct/set_show修改商品状态
PUTproduct/stock/uploadStoreProduct/uploadStock同步商品库存

商品列表支持cate_id、store_name、type、is_live、is_new、is_virtual、is_presale等筛选参数,控制器会依据cate_id是否为顶级分类自动映射为sid或cid查询条件(见 StoreProduct.php),底层列表查询由 OutStoreProductServices::searchList 完成,并补充cate_name分类名。

新增商品save参数与 CRMEB 商品模型完全对齐,包括store_name、keyword、unit_name、store_info、slider_image、video_open/link、spec_type、items/attrs(单多规格)、description、freight/postage/temp_id(运费)、give_integral、presale(预售)、vip_product(会员价)、activity(活动优先级)、recommend(推荐位)、is_limit/limit_type/limit_num(限购)等 30 余个字段,完整定义见 StoreProduct.php。

库存同步是 ERP 类合作方高频使用的接口:PUT /product/stock/upload接收items数组(每项含bar_code与qty),控制器限制单次最多 100 条并强制校验两个字段(见 StoreProduct.php)。底层 syncStock 按bar_code批量更新规格库存,并通过ProductStockJob::dispatch('distribute', ...)异步重算商品总库存。

订单(mark: order)

方法路径控制器动作说明
GETorder/listStoreOrder/lst订单列表
GETorder/:order_idStoreOrder/read订单详情
PUTorder/remark/:order_idStoreOrder/remark修改备注信息
PUTorder/receive/:order_idStoreOrder/receive确认收货
GETorder/express_listStoreOrder/express获取物流公司
PUTorder/delivery/:order_idStoreOrder/delivery订单发货
PUTorder/distribution/:order_idStoreOrder/updateDistribution修改配送信息
GETorder/split_cart_info/:order_idStoreOrder/splitCartInfo获取订单可拆分商品列表
PUTorder/split_delivery/:order_idStoreOrder/splitDelivery拆单发货
PUTorder/invoice/:order_idStoreOrder/setInvoice修改订单发票
PUTorder/invoice_status/:order_idStoreOrder/setInvoiceStatus修改订单发票状态

订单列表支持status(0 未发货 / 1 已发货 / 2 已收货 / 3 已完成 / -2 已退款)、real_name、pay_type、data(下单时间区间)、paid、type、order、field_key等筛选,查询实现在 OutStoreOrderServices::getOrderList。返回数据会补充pay_type_name、items(含cart_id、store_name、suk、image、price、cart_num、surplus_num、refund_num)等字段。

订单发货PUT /order/delivery/:order_id接收delivery_name、delivery_id、delivery_code三个字段(见 StoreOrder.php),并固定写入express_record_type = 1、type = 1表示“后台/外部发货”。

拆单发货先通过split_cart_info获取可拆分商品列表,再调用split_delivery提交cart_ids(每项含cart_id、cart_num),控制器会逐项强校验并转整型(见 StoreOrder.php)。

发票相关接口对抬头类型(个人/企业)、税号格式、手机号、银行卡号等做了正则校验(见 StoreOrder.php),开票/回传票号等操作可通过setInvoiceStatus完成。

售后/退款(mark: refund)

方法路径控制器动作说明
GETrefund/listRefundOrder/lst售后订单列表
PUTrefund/remark/:order_idRefundOrder/remark售后订单备注
PUTrefund/:order_idRefundOrder/refundPrice售后订单退款
PUTrefund/agree/:order_idRefundOrder/agree商家同意退款
PUTrefund/refuse/:order_idRefundOrder/refuse商家拒绝退款
GETrefund/:order_idRefundOrder/read售后订单详情

售后列表支持order_id、time(退款时间区间)、refund_type(1 仅退款 / 2 退货退款 / 3 拒绝退款 / 4 商品待退货 / 5 退货待收货 / 6 已退款)筛选(见 RefundOrder.php),底层由OutStoreOrderRefundServices提供服务。退款操作refundPrice通过refund_price指定退款金额,refuse需携带refund_reason拒绝原因。

优惠券(mark: coupon)

方法路径控制器动作说明
GETcoupon/listStoreCoupon/lst优惠券列表
POSTcouponStoreCoupon/save新增优惠券
PUTcoupon/status/:id/:statusStoreCoupon/status修改优惠券状态
DELETEcoupon/:idStoreCoupon/delete删除优惠券

新增优惠券支持coupon_title、coupon_price、use_min_price、coupon_time、start_use_time、end_use_time、start_time、end_time、receive_type、total_count、status等字段;当total_count = 0时自动标记为不限量(is_permanent = 1,见 StoreCoupon.php)。删除优惠券会同步清理商品与券的关联数据。

用户与用户等级(mark: user)

方法路径控制器动作说明
GETuser_level/listUserLevel/lst用户等级列表
GETuser/listUser/lst用户列表
GETuser/info/:uidUser/info用户详情
POSTuserUser/save新增用户
PUTuser/:uidUser/update修改用户
PUTuser/give_balance/:uidUser/giveBalance赠送余额
PUTuser/give_point/:uidUser/givePoint赠送积分
PUTuser/change_balance/:uidUser/changeBalance修改余额
PUTuser/change_point/:uidUser/changePoint修改积分

用户列表支持nickname、status、field_key筛选;新增/修改用户支持real_name、phone、mark、pwd、level、spread_open、is_promoter、status字段(见 User.php)。余额/积分赠送接口通过money_status/integration_status(1 增加 / 2 减少)与money/integration完成增减操作,changeBalance/changePoint则直接设置目标值。

接口权限:rules 与 verifyAuth

对外接口做到了“按账号授权”,而不是“拿到 token 全放行”。账号表eb_out_account中的rules字段以逗号分隔保存了该账号可访问的系统路由 ID 列表(见 crmeb.sql),后台创建账号时通过implode(',', $data['rules'])写入(见 SystemOutAccount.php)。

每次请求经过AuthTokenMiddleware时,OutInterfaceServices::verifyAuth($request)会执行如下校验(见 OutInterfaceServices.php):

  1. 取当前请求路由规则request->rule()->getRule()与 HTTP 方法,统一转小写;
  2. 从系统路由表SystemRouteServices查询该账号rules内且app_name == 'outapi'的路由,按 method 分组为rolesAuth[method][];
  3. 先做规则精确匹配;不匹配时,再把<>路由占位符替换为{}后二次匹配(兼容不同路由语法);
  4. 仍未匹配则抛AuthException(110000)拒绝访问。

也就是说,第三方账号的开放范围完全由后台分配的rules决定——给某个账号勾选哪些接口,它就只能调用哪些接口,实现“仅开放必要接口”的安全目标。

账号与接口文档的后台管理

对外账号的完整生命周期由管理后台「设置 → 对外接口账号」管理,控制器为 SystemOutAccount.php,路由见 crmeb/app/adminapi/route/setting.php:

  • system_out_account/index:对外接口账号信息列表;
  • system_out_account/save:新增账号(appid、appsecret、title、rules);
  • system_out_account/update/:id:修改账号(可留空 appsecret 表示不修改);
  • system_out_account/set_status/:id/:status:启用/禁用账号;
  • system_out_account/set_up/:id:设置账号推送接口;
  • system_out_account/text_out_url:测试获取推送 token 接口;
  • system_out_interface/list:对外接口列表(按分类树形返回,见 OutInterfaceServices::outInterfaceList);
  • system_out_interface/save/:id、/info/:id、/edit_name、/del/:id:对外接口文档的增删改查。

新增账号时appsecret使用password_hash(..., PASSWORD_DEFAULT)加密存储、登录时password_verify比对,账号与密钥校验规则(appid 4~30 位字母数字、appsecret 6~32 位)定义在 StoreOutAccountValidate.php。

账号还可配置事件推送(outSetUpSave,见 SystemOutAccount.php):push_open(是否推送)、push_account/push_password(第三方推送账号)、push_token_url(第三方获取 token 接口)、user_update_push(用户更新推送)、order_create_push(订单创建推送)、order_pay_push(订单支付推送)、refund_create_push(售后创建推送)、refund_cancel_push(售后取消推送)。eb_out_account表中的对应字段定义见 crmeb.sql,OutAccountServices::textOutUrl()则实现了后台“测试获取 token 接口”的连通性验证(见 OutAccountServices.php)。

异常处理与全局配置

对外应用通过 provider.php 将全局异常处理器覆盖为OutApiExceptionHandle,实现“对外表现可控”:

  • report()只对非忽略类异常写错误日志,且日志以|分隔记录用户 ID、IP、耗时、请求方法、路由、参数与报错数据(见 OutApiExceptionHandle.php);ValidateException、AuthException、AdminException、ApiException列入ignoreReport不落日志;
  • render()对上述业务异常返回标准 JSON 结构(status+msg),调试模式下才附带message/file/line/trace等细节,避免把内部堆栈暴露给第三方(见 OutApiExceptionHandle.php)。

本应用的路由配置在 crmeb/app/outapi/config/route.php:强制使用路由、合并路由规则、路由完全匹配、关闭控制器/操作名自动转换,保证对外 URL 的稳定与 RESTful 语义不被改写。路由组最外层挂载AllowOriginMiddleware(见 route.php)以处理跨域,同时Route::miss对 OPTIONS 预检请求返回 200 与允许跨域头、对未知路径统一返回 404。

数据结构:两张核心表

对外能力依赖两张数据表(完整建表语句见 crmeb.sql):

eb_out_account(对外接口账号):id、appid(账号)、appsecret(密钥,bcrypt 密文)、title(描述)、status(状态)、rules(可访问接口权限,逗号分隔的 SystemRoute ID)、add_time、last_time、ip、is_del,以及push_open等 7 个推送配置字段。

eb_out_interface(对外接口):id、pid(父级,用于组织分类)、type(0 菜单 / 1 接口)、name、describe、method、url、request_params、return_params、request_example、return_example、error_code、is_del。安装包中预置了数十条接口文档数据(如“获取 access_token”“用户列表”“商品详情”“订单列表”“同意退款”等),字段中 JSON 化的请求/返回参数结构,为第三方联调提供了可直接参考的请求示例与返回示例,这也是后台“对外接口列表”的数据来源。

小结

CRMEB 的outapi应用目录通过“独立应用 + JWT 令牌 + 账号级接口权限 + RESTful 路由 + 独立异常处理”的组合,在不引入登录态的前提下把商城核心能力安全地开放给了合作第三方。若你需要对接 ERP、自研 APP 或第三方分销系统,可以依照本文的目录结构、认证流程与接口清单,在 crmeb/app/outapi/route/route.php 中扩展新路由、在controller/下新增资源控制器,并复用app/services/out与各Out*Services完成业务实现;需要新增对外账号与分配接口权限时,则到管理后台的「对外接口账号」中配置rules即可。

  • 后端
  • 电商
  • 前端

【免费下载链接】CRMEB

🔥CRMEB开源商城免费开源多语言商城系统,Tp6框架商城,系统可商用;包含小程序商城、H5商城、公众号商城、PC商城、App,支持分销、拼团、砍价、秒杀、优惠券、积分、会员等级、小程序直播、页面DIY,前后端分离,方便二开,更有详细使用文档、接口文档、数据字典、二开文档/视频教程,欢迎大家提出宝贵意见和建议

项目地址:https://gitcode.com/gh_mirrors/cr/CRMEB
点击查看免费下载

相关推荐

上一篇:Burp Suite 汉化完整指南:一条命令开启全中文界面,不碰原始代码
下一篇:5分钟搞定数据恢复:TestDisk与PhotoRec开源分区修复与文件找回全攻略

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询