You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用自定义NodeJS服务器在Shopify店铺安全展示额外客户数据

实现方案核心逻辑

你当前的客户面店铺页面场景不需要使用App Bridge(App Bridge仅用于Shopify后台嵌入式应用开发),直接用Shopify官方提供的App Proxy即可满足所有安全要求:

  • App Proxy会作为中转层,所有前端请求先到Shopify再转发到你的NodeJS API,避免暴露你的API真实地址
  • Shopify会自动在转发请求里注入已登录用户的ID,伪造无效
  • 自带签名校验机制,可确保请求确实来自你指定的Shopify店铺
  • 避免你原来直接在URL传邮箱的安全风险:明文传邮箱很容易被篡改遍历,泄露所有用户数据
分步实现教程

第一步:配置Shopify App Proxy

  • 进入你的Shopify合作伙伴后台,找到对应应用,进入「应用代理」配置页
  • 代理路径自定义即可,比如前缀选/a,子路径填customer-data,后续店铺内访问/a/customer-data就会自动转发到你的NodeJS API
  • 代理URL填你的NodeJS服务的接口地址,比如https://你的API域名/shopify/customer-data
  • 保存配置后,Shopify会生成专属的签名密钥,后续服务端校验要用到,存在你的服务端环境变量里即可。

第二步:Liquid模板注入安全参数

不要在请求里传明文邮箱,Shopify的Liquid自带全局变量,只有已登录用户才会生成customer变量,直接把官方的客户ID和店铺域名注入给Vue组件即可:

{% if customer %}
<!-- 仅已登录用户才会渲染Vue组件,未登录用户访问/account页Shopify会自动跳转到登录页 -->
<div id="vue-app" data-customer-id="{{ customer.id }}" data-shop-domain="{{ shop.permanent_domain }}"></div>
{% endif %}

Vue组件内发送请求的时候,直接调用App Proxy地址,不要直接请求你的NodeJS API地址:

// Vue组件请求逻辑示例
const customerId = document.getElementById('vue-app').dataset.customerId
const shopDomain = document.getElementById('vue-app').dataset.shopDomain
// 请求走Shopify App Proxy中转,不直接暴露你的API地址
fetch(`/a/customer-data?customer_id=${customerId}&shop_domain=${shopDomain}`)
  .then(res => res.json())
  .then(data => {
    // 处理返回的自定义客户数据
  })

第三步:NodeJS(Express/Feathers)端三层安全校验

这一步是核心,所有校验通过后再返回用户数据:

1. 编写App Proxy签名校验中间件

首先校验请求确实是Shopify官方转发的,不是伪造的,Express示例如下,Feathers可以直接封装成钩子使用:

import crypto from 'crypto'

const validateShopifyProxySignature = (req, res, next) => {
  const { signature, ...query } = req.query
  // 先校验时间戳,防止重放攻击,超过5分钟的请求直接拒绝
  if (Date.now() / 1000 - Number(query.timestamp) > 300) {
    return res.status(401).send('请求超时')
  }
  // 按照Shopify官方规则生成校验哈希:把所有参数按键升序排序拼接,用App Proxy密钥做HMAC SHA256加密
  const sortedQueryStr = Object.keys(query).sort().map(key => `${key}=${query[key]}`).join('')
  const computedHash = crypto.createHmac('sha256', process.env.SHOPIFY_APP_PROXY_SECRET).update(sortedQueryStr).digest('hex')
  // 哈希对比不一致直接拒绝
  if (computedHash !== signature) {
    return res.status(403).send('非法请求')
  }
  next()
}

2. 身份与权限校验

签名校验通过后,再验证用户身份和访问权限:

// 你的API接口逻辑
app.get('/shopify/customer-data', validateShopifyProxySignature, async (req, res) => {
  const { logged_in_customer_id, customer_id, shop_domain } = req.query
  // 校验1:logged_in_customer_id是Shopify官方注入的参数,存在才说明用户已登录
  if (!logged_in_customer_id) {
    return res.status(401).send('请先登录店铺')
  }
  // 校验2:前端传的客户ID必须和Shopify注入的登录用户ID一致,防止用户篡改参数访问他人数据
  if (logged_in_customer_id !== customer_id) {
    return res.status(403).send('无权访问他人数据')
  }
  // 校验3:仅允许你指定的店铺访问,防止其他店铺的请求打到你的API
  if (shop_domain !== process.env.ALLOWED_SHOP_DOMAIN) {
    return res.status(403).send('不允许的店铺访问')
  }
  // 所有校验通过后,拿客户ID去你的数据库查询对应绑定的邮箱,再返回关联的自定义数据即可
  const userData = await 你的数据库查询方法({ shopify_customer_id: customer_id })
  if (!userData) {
    return res.status(404).send('未查询到对应数据')
  }
  res.json(userData)
})

第四步:额外安全加固

  • 你的NodeJS API不要开启跨域配置,所有请求必须走App Proxy中转,避免外部直接调用
  • 给接口加频率限制,防止被暴力爬取
  • 永远不要在前端请求中传输邮箱、手机号等敏感信息,所有身份校验依赖Shopify官方注入的可信参数

内容的提问来源于stack exchange,提问作者Laurensius Adi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 05:48:01