一、前言
在之前的系列文章中,我写了 LikeShop 多商户版的商品模块、分账对接和安全加固。这一篇聚焦用户体系的入口——微信登录与会员体系。
微信登录是 LikeShop 用户获取的第一个环节,也是最容易出问题的环节之一。有一个真实的踩坑案例:开发者在配置微信小程序登录时,前端调起wx.login后,后台一直返回 401 提示“签名错误”。检查了 appid、secret、支付密钥都没问题,最后发现多商户版需要在平台后台额外配置一个开放平台第三方平台 AppID,因为要处理商家独立登录态。
这个坑的根源,是多商户版的登录态体系和单商户版有本质区别。单商户版一套小程序对应一个商户,登录态是扁平的;多商户版平台下有几十上百个商户,每个商户可能都有自己的小程序,但用户是平台级的,登录态需要在服务端统一管理。
这篇文章就从 OAuth 流程、用户表设计、会员体系三个层面,把 LikeShop 多商户版的用户体系拆开讲清楚。
二、微信登录 OAuth 流程
2.1 登录方式的配置项
LikeShop 的微信登录不是“写死”的,而是通过后台配置开关控制的。公共配置接口GET /shopapi/config/getConfig返回的登录相关参数如下:
| 参数名 | 类型 | 说明 |
|---|---|---|
| register_way | array | 注册方式:1-手机号码注册 |
| login_way | array | 登录方式:1-手机号码密码登录;2-手机短信验证码登录 |
| is_mobile_register_code | int | 手机号码注册需验证码:0-关闭;1-开启 |
| coerce_mobile | int | 强制绑定手机:0-关闭;1-开启 |
| h5_wechat_auth | int | 公众号-微信授权登录:0-关闭;1-开启 |
| h5_auto_wechat_auth | int | 公众号-自动微信授权登录:0-关闭;1-开启 |
| mnp_wechat_auth | int | 微信小程序-微信授权登录:0-关闭;1-开启 |
| mnp_auto_wechat_auth | int | 微信小程序-自动微信授权登录:0-关闭;1-开启 |
| app_wechat_auth | int | APP-微信授权登录:0-关闭;1-开启 |
h5_auto_wechat_auth和mnp_auto_wechat_auth的区别需要特别理解:“授权登录”需要用户手动点击授权按钮,“自动授权登录”是页面加载时静默触发授权。自动授权的用户体验更好,但需要用户之前已经授权过,否则微信会直接跳转到授权页。
2.2 小程序端 OAuth 流程
微信小程序的登录流程和 H5 完全不同。小程序的流程是:通过wx.login()获取 code 再换取 openid,而 H5 在微信环境下走公众号授权。
小程序端的完整登录链路如下:
用户点击登录 ↓ ① wx.login() 获取 code ↓ ② 将 code 发送到服务端 /shopapi/user/mnpLogin ↓ ③ 服务端调用微信接口换取 openid 和 session_key ↓ ④ 服务端查找或创建用户,生成 token 返回 ↓ ⑤ 前端将 token 存储到本地 ↓ ⑥ 后续请求自动携带 token这里有一个关键约束:code 只能使用一次,且有效期很短。前端拿到 code 后应立刻发送给服务端,不要在本地缓存。二开时如果遇到“登录返回 401”或“code 无效”的报错,通常是因为 code 被重复使用或超时了。
2.3 多商户版的核心差异:商家独立登录态
多商户版和单商户版在微信登录上最大的区别是:多商户版需要处理商家独立登录态。
在多商户版中,平台、商户、C 端用户是三个独立的登录态体系。平台端管理商户和审核,商户端管理自己的店铺和商品,C 端用户是购物者。这三套登录态共用同一个微信授权体系,但 session 是隔离的。
技术实现上,这意味着同一微信用户在不同角色下的身份标识不能混用。平台管理员登录时生成的 token 只能访问管理后台接口,C 端用户登录时生成的 token 只能访问商城接口。二开时如果要在某个端新增登录入口,必须明确这个入口对应哪个角色体系,生成的 token 要限定在对应的权限范围内。
2.4 微信配置的关键步骤
多商户版的微信配置比单商户版多了一个步骤。除了配置小程序自身的 AppID 和 AppSecret 之外,还需要在平台后台的“微信设置”中额外填写开放平台第三方平台 AppID。
公众号的服务器配置也需要在 LikeShop 后台和微信公众号后台同步配置 Token 和 EncodingAESKey。配置完成后,用户关注公众号即可触发微信授权登录流程。
三、用户表设计
3.1 ls_user 用户主表
ls_user是整个系统的用户中心,所有与用户相关的数据都围绕这张表展开。
| 字段名 | 数据类型 | 注释 |
|---|---|---|
| id | int | 主键 |
| sn | varchar | 会员码(唯一标识) |
| nickname | varchar | 用户昵称 |
| avatar | varchar | 用户头像 |
| mobile | varchar | 手机号码 |
| level | tinyint | 用户等级 |
| group_id | int | 所属分组id |
| sex | tinyint | 性别:0-未知;1-男;2-女 |
| user_money | decimal | 用户余额 |
| earnings | decimal | 佣金收益 |
level字段是会员体系的核心。如果你要做会员等级折扣,这个字段就是判断依据。等级值越大,通常对应更高的折扣比例。user_money是余额字段,退款到余额、分销佣金提现等操作都会修改这个字段,修改时要注意并发安全——LikeShop 通过ls_account_log账户流水表来保证资金变动的可追溯性。
3.2 用户与 openid 的映射关系
多商户版中,用户和微信 openid 的映射关系不是直接存在ls_user表中,而是通过独立的授权表管理。微信的标识体系有两个层级:openid 是用户在某个具体应用(公众号/小程序)中的唯一标识,unionid 是用户在同一个微信开放平台账号下的全局唯一标识。
在多商户场景下,一个用户可能同时使用多个商户的小程序。如果每个小程序都生成独立的 openid,同一个用户在不同商户的小程序下会被识别为不同的人,无法实现“全终端数据打通”。
LikeShop 的解决方案是以 unionid 作为用户的全局标识。用户在任一终端授权登录时,服务端优先用 unionid 查找用户,如果找到则直接关联;如果找不到,再用 openid 创建新用户。
二开时如果新增了微信登录入口(比如抖音小程序),需要确保这个入口也能获取到 unionid 并写入授权表,否则跨端用户无法关联。
3.3 多商户版的用户隔离问题
这里有一个需要特别说明的设计:LikeShop 多商户版的 C 端用户是平台级的,不是商户级的。用户在整个平台注册一次,就能在所有商户的店铺下单。但用户的会员等级、余额、积分也是平台级的。
这对二开的影响是:如果业务要求“不同商户下的会员等级独立”,需要在ls_user之外新增一张“用户-商户关联表”,存储用户在每个商户下的等级和积分。但这样做会带来一个后果——平台级的会员权益(比如全平台通用的余额)和商户级的权益需要分开管理,复杂度会上升。
四、会员体系设计
4.1 会员等级
LikeShop 的会员等级体系以成长值作为升级条件。后台设置会员等级,用于商品的折扣。会员根据设定好的等级成长值升级,等级成长值通过日常消费积累。
赠送成长值支持订单支付、订单发货、订单完成、订单结算时赠送,防止刷取成长值现象。赠送的成长值不会收回。
新增会员等级需要填写等级名称、成长值、等级图标、等级背景图以及会员折扣等字段。等级折扣的设置有两个选项:0-无等级折扣;1-参与等级折扣。
4.2 会员等级与商品价格的联动
会员等级与商品价格的联动,核心在价格计算的优先级上。之前写商品模块时提到过,LikeShop 的价格优先级是:活动价 > 会员价 > 原价。
这意味着,如果商品参与了秒杀或拼团活动,会员价不再生效,成交价就是活动价。二开时如果要求“会员价在活动价基础上再打折”,需要修改价格计算的优先级,但这样做会导致活动利润被进一步压缩,需要与运营团队确认可行性。
4.3 会员体系与营销模块的协作
会员体系不是孤立运转的,它和营销模块(优惠券、积分、分销)的协作关系如下:
| 模块 | 与会员体系的交互 |
|---|---|
| 优惠券 | 会员可使用优惠券,但优惠券不改变会员等级 |
| 积分 | 会员消费可获得积分,积分可抵扣订单金额 |
| 分销 | 会员可成为分销员,佣金计入earnings字段 |
| 成长值 | 订单支付/发货/完成/结算时赠送,用于等级升级 |
4.4 二开扩展点
新增会员等级条件:目前 LikeShop 的等级条件是成长值。如果要新增“按累计消费金额”的等级条件,需要在等级配置表中新增字段,并在用户成长值更新的 Logic 中增加判断逻辑。
会员等级过期机制:当前 LikeShop 没有等级过期机制。如果业务要求“会员等级每 6 个月重新计算”,需要新增一个定时任务,定期扫描用户成长值并重新计算等级。
用户标签与分组:ls_user.group_id字段用于用户分组。如果要做更复杂的用户标签体系(一个用户可以打多个标签),需要新建用户-标签关联表,而不是在ls_user中堆砌字段。
五、二开避坑清单
坑一:多商户版微信登录 401 签名错误。最常见的原因是只配置了商户自己的小程序信息,没有在平台后台配置开放平台第三方平台 AppID。多商户版必须额外配置这一项。
坑二:小程序 code 复用。wx.login()获取的 code 只能使用一次。每次登录都需要重新调用wx.login()获取新的 code。
坑三:token 失效后登录页循环跳转。如果登录页本身也需要请求接口,token 失效时登录页的请求也会返回-1,导致反复跳转自己。解决方案是在请求封装中排除登录相关的接口。
坑四:跨端用户无法关联。如果新增的微信登录入口没有获取 unionid,同一个用户在不同终端会被识别为不同的人。所有微信登录入口都必须确保 unionid 被正确写入授权表。
坑五:直接修改ls_user的 level 字段。会员等级变更应该走UserLogic中定义的方法,确保等级变更和成长值计算在同一事务中完成,避免出现“等级已升级但成长值未更新”的不一致情况。
六、总结
LikeShop 多商户版的微信登录与会员体系,核心可以概括为三条线:
OAuth 流程:小程序端通过wx.login()获取 code 换取 openid,H5 端走公众号授权。登录方式通过后台配置开关控制。多商户版需要额外配置开放平台第三方平台 AppID 来处理商家独立登录态。
用户表设计:ls_user是用户中心,level字段是会员等级,user_money是余额,earnings是佣金收益。用户与微信的映射通过授权表管理,以 unionid 作为全局标识。
会员体系:以成长值为升级条件,成长值通过日常消费积累。价格优先级为活动价 > 会员价 > 原价。会员体系与优惠券、积分、分销模块协同工作。
二开时守住两条底线:所有微信登录入口必须获取 unionid、会员等级变更必须走 UserLogic。
本文基于 LikeShop 多商户版 源码及官方开发文档整理,不同版本的字段定义和接口路径可能略有差异,请以实际源码和对应版本的开发文档为准。