第三方登录接口文档
版本:V2.2
更新日期:2026-07-15
变更说明:新增 remarks 字段,用于传递拒绝原因等备注信息
1. 概述
本套接口用于第三方系统与药汇购之间的用户数据互通,包含两个接口:
| # |
接口 |
路径 |
鉴权 |
职责 |
| 登录接口 |
按手机号签发 Token |
POST /api/auth/external/miniapp-token |
X-Api-Key |
查找/注册用户 + 更新资料 + 同步入驻信息,返回 Token |
| 同步接口 |
信息同步(独立) |
POST /api/auth/external/sync |
X-Api-Key |
更新用户资料 + 同步入驻信息(需用户已存在) |
💡 两种使用方式:
- 一步到位:登录接口直接传入全部字段(手机号 + 用户信息 + 入驻信息),一次请求完成登录和信息同步
- 分步调用:先调登录接口获取 Token,再调同步接口更新详细资料和入驻资质
核心特性:
- 按手机号自动查找或注册用户
- 支持双渠道:
loginSource=MINIAPP(小程序,30天过期,不踢PC) / loginSource=PC(PC端,1小时过期,踢旧PC会话),不传默认 MINIAPP
- 支持传入
skipRefreshToken=true 仅获取 accessToken,不生成/覆盖 refreshToken
- 新用户自动初始化 PLUS 会员(普通会员)
- 第三方已审核用户(
status=1)自动赠送 30 天 PRO 高级会员
- 支持传入小程序
openId / unionId,支付场景无需重复授权
- 已存在用户的入驻信息仅允许更新审核状态,其他字段保留原值(后续由运营端确认更新)
2. 鉴权方式
两个接口均使用 API Key 鉴权,在请求头中传入:
X-Api-Key: {我方提供的API Key}
| 参数名 |
类型 |
必填 |
说明 |
X-Api-Key |
String |
是 |
接口鉴权密钥 |
Content-Type |
String |
是 |
固定值 application/json |
⚠️ 请妥善保管 API Key,不要泄露到前端代码或客户端。请在后端服务中调用此接口。
3. 登录接口(miniapp-token)
3.1 接口信息
| 项目 |
说明 |
| 接口名称 |
外部系统换取登录 Token |
| 请求方式 |
POST |
| 接口路径 |
/api/auth/external/miniapp-token |
| Content-Type |
application/json |
💡 登录接口支持登录 + 信息同步一体化:除了必传手机号外,可选择性传入用户资料和入驻信息字段,一步完成登录和信息同步。
3.2 请求参数
必填字段
| 参数名 |
类型 |
必填 |
说明 |
phone |
String |
是 |
用户手机号 |
登录控制字段
| 参数名 |
类型 |
必填 |
说明 |
inviteCode |
String |
否 |
邀请码(仅新用户注册时生效) |
loginSource |
String |
否 |
登录来源。MINIAPP(小程序,30天过期,不踢PC) / PC(PC端,1小时过期,踢旧PC会话)。不传默认 MINIAPP |
skipRefreshToken |
Boolean |
否 |
true=仅返回 accessToken(refreshToken 返回 null),适用于客户端已持有 refreshToken 仅需换 accessToken 的场景;不传默认 false |
用户信息字段(全部可选,非空才写入/覆盖)
| 参数名 |
类型 |
必填 |
说明 |
对应我方字段 |
username |
String |
否 |
用户名(保存到 userName 字段;若未传 nickname,则自动作为 nickname 的兜底值) |
user_name |
nickname |
String |
否 |
昵称(不传则依次取 username、手机号后4位生成) |
nickname |
pharmacyName |
String |
否 |
药店名称 |
pharmacy_name |
province |
String |
否 |
省 |
province |
city |
String |
否 |
市 |
city |
district |
String |
否 |
区 |
district |
pharmacyAddress |
String |
否 |
药店详细地址 |
pharmacy_address |
contactPerson |
String |
否 |
联系人 |
contact_person |
contactPhone |
String |
否 |
联系电话 |
contact_phone |
businessLicenseNo |
String |
否 |
营业执照号(统一社会信用代码) |
business_license_no |
openId |
String |
否 |
微信小程序 openId(保存到 wechat_mini_open_id) |
wechat_mini_open_id |
unionId |
String |
否 |
微信开放平台 unionId(跨应用用户统一标识) |
wechat_union_id |
入驻信息字段(全部可选,传入后同步写入 t_business_license)
| 参数名 |
类型 |
必填 |
说明 |
对应我方字段 |
storeName |
String |
否 |
店铺名称(不传则使用 pharmacyName 兜底) |
store_name |
terminalType |
String |
否 |
终端类型:SINGLE-单店 / CHAIN-连锁 / CLINIC-诊所 / COMMUNITY_HEALTH-社康 |
terminal_type |
businessLicenseUrl |
String |
否 |
营业执照图片URL |
license_image_url |
drugLicenseUrl |
String |
否 |
药品经营许可证图片URL |
drug_license_url |
medicalDeviceClass2Url |
String |
否 |
二类医疗器械备案图片URL |
medical_device_class2_url |
medicalDeviceClass3Url |
String |
否 |
三类医疗器械备案图片URL |
medical_device_class3_url |
status |
Integer |
否 |
审核状态:0-审核中 / 1-审核成功 / 2-审核失败(不传默认0) |
— |
remarks |
String |
否 |
备注(如拒绝原因等) |
remark |
3.3 请求示例
最简请求(默认小程序,30天过期)
{
"phone": "13800138000"
}
PC端登录(1小时过期)
{
"phone": "13800138000",
"loginSource": "PC"
}
仅刷新 accessToken(不生成新 refreshToken)
{
"phone": "13800138000",
"loginSource": "MINIAPP",
"skipRefreshToken": true
}
一步到位(登录 + 用户信息 + 入驻信息)
{
"phone": "13800138000",
"loginSource": "MINIAPP",
"username": "yaohuigou001",
"nickname": "药汇购001",
"pharmacyName": "北京同仁堂大药房",
"province": "北京市",
"city": "北京市",
"district": "朝阳区",
"pharmacyAddress": "建国路88号",
"contactPerson": "张三",
"contactPhone": "13800138000",
"businessLicenseNo": "91110105MA12345678",
"openId": "oJx1x5xxxxxxxxxxxxxxxxx",
"unionId": "oABCD1234xxxxxxxxxxxxxx",
"storeName": "北京同仁堂大药房(朝阳分店)",
"terminalType": "SINGLE",
"businessLicenseUrl": "https://oss.example.com/yyzz.jpg",
"drugLicenseUrl": "https://oss.example.com/ypjy.jpg",
"medicalDeviceClass2Url": "https://oss.example.com/elqx.jpg",
"medicalDeviceClass3Url": "https://oss.example.com/slqx.jpg",
"status": 1,
"remarks": "资料审核不通过,缺少药品经营许可证"
}
3.4 响应参数
通用响应结构
{
"code": 200,
"message": "success",
"data": { }
}
| 字段 |
类型 |
说明 |
code |
int |
状态码,200 表示成功 |
message |
String |
提示信息 |
data |
Object |
登录响应数据 |
data 字段
| 参数名 |
类型 |
说明 |
userId |
String |
用户ID(字符串,避免JS大数精度丢失) |
accessToken |
String |
访问令牌 |
refreshToken |
String |
刷新令牌(skipRefreshToken=true 时为 null) |
expiresIn |
Long |
accessToken有效期(秒):MINIAPP=2592000(30天),PC=3600(1小时) |
newUser |
Boolean |
是否为新注册用户 |
needBindPhone |
Boolean |
始终返回false |
role |
String |
固定值"USER" |
userInfo |
Object |
用户基本信息 |
userInfo 字段
| 参数名 |
类型 |
说明 |
id |
String |
用户ID |
phone |
String |
手机号 |
nickname |
String |
昵称 |
userName |
String |
第三方传入的原始用户名 |
avatar |
String |
头像 URL |
wechatBound |
Boolean |
是否已绑定微信 |
loginSource |
String |
登录来源,"MINIAPP" 或 "PC" |
pharmacyName |
String |
药店名称 |
province |
String |
省 |
city |
String |
市 |
district |
String |
区 |
membershipLevel |
String |
会员等级代码(PLUS / PRO / ULTRA) |
membershipLevelName |
String |
会员等级名称 |
licenseStatus |
String |
营业执照审核状态 |
inviterId |
String |
邀请人用户ID |
inviterNickname |
String |
邀请人昵称 |
hasBoundInviteCode |
Boolean |
是否已绑定邀请码 |
createTime |
String |
注册时间 |
响应示例
{
"code": 200,
"message": "success",
"data": {
"userId": "1234567890123456789",
"accessToken": "eyJhbGciOiJIUzI1NiJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiJ9...",
"expiresIn": 2592000,
"newUser": false,
"needBindPhone": false,
"role": "USER",
"userInfo": {
"id": "1234567890123456789",
"phone": "138****8000",
"nickname": "用户8000",
"userName": null,
"avatar": null,
"wechatBound": false,
"loginSource": "MINIAPP",
"pharmacyName": "北京同仁堂大药房",
"province": "北京市",
"city": "北京市",
"district": "朝阳区",
"membershipLevel": "PRO",
"membershipLevelName": "高级会员",
"licenseStatus": "APPROVED",
"inviterId": "1234567890123456788",
"inviterNickname": "邀请人昵称",
"hasBoundInviteCode": true,
"createTime": "2025-01-01T12:00:00"
}
}
}
4. 信息同步接口(sync)
4.1 接口信息
| 项目 |
说明 |
| 接口名称 |
外部系统信息同步 |
| 请求方式 |
POST |
| 接口路径 |
/api/auth/external/sync |
| Content-Type |
application/json |
⚠️ 用户必须先通过登录接口创建后,才能调用本接口同步信息。如果手机号对应的用户不存在,将返回错误。
4.2 请求参数
必填字段
| 参数名 |
类型 |
必填 |
说明 |
phone |
String |
是 |
用户手机号(用于定位用户) |
用户信息字段(全部可选,非空才覆盖)
| 参数名 |
类型 |
必填 |
说明 |
username |
String |
否 |
用户名 |
nickname |
String |
否 |
昵称 |
pharmacyName |
String |
否 |
药店名称 |
province |
String |
否 |
省 |
city |
String |
否 |
市 |
district |
String |
否 |
区 |
pharmacyAddress |
String |
否 |
药店详细地址 |
contactPerson |
String |
否 |
联系人 |
contactPhone |
String |
否 |
联系电话 |
businessLicenseNo |
String |
否 |
营业执照号 |
openId |
String |
否 |
微信小程序 openId |
unionId |
String |
否 |
微信开放平台 unionId |
入驻信息字段(全部可选)
⚠️ 重要:入驻信息已存在记录时,仅允许更新审核状态(status),其他字段(店名、地区、证照图片等)保留原值,不允许通过第三方接口覆盖。后续修改需通过运营端确认。
| 参数名 |
类型 |
必填 |
说明 |
storeName |
String |
否 |
店铺名称(不传则用 pharmacyName 兜底) |
terminalType |
String |
否 |
终端类型 |
businessLicenseUrl |
String |
否 |
营业执照图片URL |
drugLicenseUrl |
String |
否 |
药品经营许可证图片URL |
medicalDeviceClass2Url |
String |
否 |
二类医疗器械备案图片URL |
medicalDeviceClass3Url |
String |
否 |
三类医疗器械备案图片URL |
status |
Integer |
否 |
审核状态:0-审核中 / 1-审核成功 / 2-审核失败(不传默认0) |
remarks |
String |
否 |
备注(如拒绝原因等) |
4.3 审核状态说明
status=1:审核状态设为 APPROVED(审核通过),首次通过赠送 30 天 PRO 高级会员
status=0 或不传:审核状态设为 PENDING(待运营审核)
status=2:审核状态设为 REJECTED(审核失败)
- PENDING/REJECTED 状态可随
status 更新(含互转、升级到 APPROVED)
- 已 APPROVED 的记录再次同步时:更新入驻字段并重置为 PENDING,需重新审核;奖励仅首次发放,不会重复
4.4 入驻信息更新规则
💡 核心原则:以第三方传入的最新数据为准,非空字段直接覆盖本地记录。
| 场景 |
行为 |
| 首次同步(无入驻记录) |
创建新记录,写入全部字段 |
| 已存在记录(非 APPROVED) |
以第三方传入字段覆盖本地,同时更新审核状态 |
| 已存在记录(已 APPROVED) |
以第三方传入字段覆盖本地,状态重置为 PENDING 待重新审核;奖励标记保留,不重复发放 |
| 需修改入驻信息 |
第三方再次调用同步接口即可更新,无需人工介入 |
4.5 请求示例
{
"phone": "13800138000",
"username": "yaohuigou001",
"nickname": "药汇购新昵称",
"pharmacyName": "北京同仁堂大药房",
"province": "北京市",
"city": "北京市",
"district": "朝阳区",
"status": 1,
"remarks": "资料审核不通过"
}
4.6 响应
{
"code": 200,
"message": "success",
"data": null
}
响应 code=200 表示同步成功,无 data 内容。
5. 错误码
| 错误码 |
说明 |
处理建议 |
200 |
成功 |
— |
401 |
API Key 无效或缺失 |
检查X-Api-Key请求头 |
400 |
参数校验失败 |
检查phone是否为空 |
400 |
用户不存在(同步接口) |
先调用登录接口创建用户 |
500 |
服务器内部错误 |
重试,持续失败联系我方 |
6. Token 使用说明
6.1 携带 Token
Authorization: Bearer {accessToken}
6.2 Token 刷新
POST /api/auth/refresh
Content-Type: application/json
{ "refreshToken": "{refreshToken}" }
刷新后旧 refreshToken 立即失效(Token 旋转机制)。
6.3 心跳保活
POST /api/auth/heartbeat
Authorization: Bearer {currentAccessToken}
建议间隔:PC 端约 48 分钟(3600 × 80%),小程序端约 24 天(2592000 × 80%)。
💡 小程序端建议:已持有有效 refreshToken 时,调用登录接口传 skipRefreshToken=true 仅换新 accessToken,避免频繁生成 refreshToken。
7. 注意事项
| # |
说明 |
| 1 |
登录接口支持一步完成登录+信息同步(传入全部字段即可) |
| 2 |
同步接口要求用户已存在(先调用登录接口创建),否则返回错误 |
| 3 |
PC端单设备互踢(递增 tokenVersion),小程序与PC互不干扰 |
| 4 |
Token 过期时间:PC=1小时,小程序=30天 |
| 5 |
手机号未注册时自动创建账号并初始化 PLUS 会员 |
| 6 |
inviteCode仅新用户注册时生效 |
| 7 |
API Key请在后端调用,勿暴露到客户端 |
| 8 |
skipRefreshToken=true 时 refreshToken 返回 null |
| 9 |
每次刷新后旧 refreshToken 立即作废,请保存最新的 |
| 10 |
同步接口仅更新非空字段,不会清空已有数据 |
| 11 |
status=1 时入驻状态直接审核通过,首次通过赠送 30 天 PRO 高级会员(不重复) |
| 12 |
已审核通过的入驻记录再次同步时,更新字段并重置为 PENDING 待重新审核,不重复奖励 |
| 13 |
传入 openId/unionId 后,小程序支付无需再次 wx.login 授权 |
| 14 |
入驻信息已存在时允许更新字段,审核通过后的记录重新同步会触发重新审核流程 |
8. 调用示例
完整流程(cURL)
# 一步到位:登录 + 同步用户信息和入驻资质
curl -X POST "https://your-domain.com/api/auth/external/miniapp-token" \
-H "Content-Type: application/json" \
-H "X-Api-Key: your-api-key-here" \
-d '{
"phone": "13800138000",
"loginSource": "PC",
"username": "yaohuigou001",
"nickname": "药汇购001",
"pharmacyName": "北京同仁堂大药房",
"province": "北京市",
"city": "北京市",
"district": "朝阳区",
"pharmacyAddress": "建国路88号",
"contactPerson": "张三",
"contactPhone": "13800138000",
"businessLicenseNo": "91110105MA12345678",
"storeName": "北京同仁堂大药房(朝阳分店)",
"terminalType": "SINGLE",
"businessLicenseUrl": "https://oss.example.com/yyzz.jpg",
"drugLicenseUrl": "https://oss.example.com/ypjy.jpg",
"status": 1
}'
# 后续独立更新信息(如仅变更用户昵称)
curl -X POST "https://your-domain.com/api/auth/external/sync" \
-H "Content-Type: application/json" \
-H "X-Api-Key: your-api-key-here" \
-d '{
"phone": "13800138000",
"nickname": "新昵称"
}'
9. 字段映射表
9.1 用户信息(写入 t_users)
| 第三方传入字段 |
我方数据库字段 |
说明 |
phone |
phone |
手机号(必填,用于定位用户) |
username |
user_name |
用户名 |
nickname |
nickname |
昵称 |
pharmacyName |
pharmacy_name |
药店名称 |
province |
province |
省 |
city |
city |
市 |
district |
district |
区 |
pharmacyAddress |
pharmacy_address |
药店详细地址 |
contactPerson |
contact_person |
联系人 |
contactPhone |
contact_phone |
联系电话 |
businessLicenseNo |
business_license_no |
营业执照号 |
openId |
wechat_mini_open_id |
微信小程序 openId |
unionId |
wechat_union_id |
微信开放平台 unionId |
9.2 入驻信息(写入 t_business_license)
| 第三方传入字段 |
我方数据库字段 |
说明 |
storeName |
store_name |
店铺名称(不传则用 pharmacyName) |
terminalType |
terminal_type |
终端类型 |
businessLicenseUrl |
license_image_url |
营业执照图片URL |
drugLicenseUrl |
drug_license_url |
药品经营许可证图片URL |
medicalDeviceClass2Url |
medical_device_class2_url |
二类医疗器械备案图片URL |
medicalDeviceClass3Url |
medical_device_class3_url |
三类医疗器械备案图片URL |
status |
review_status |
审核状态:0→PENDING / 1→APPROVED / 2→REJECTED |
remarks |
remark |
备注(如拒绝原因等) |
💡 入驻记录保存时,以下字段由系统自动填入:
store_address ← 从 pharmacyAddress 提取
credit_code ← 从 businessLicenseNo 提取
sync_source ← 固定为 MINIAPP_SYNC
show_verified_badge ← 首次审核通过时设为 true
10. 联系方式
如有问题,请联系我方技术支持。
11. 变更记录
| 版本 |
日期 |
变更内容 |
| V1.0 ~ V1.7 |
2026-07-07 ~ 2026-07-11 |
初始版本、字段扩展、状态字段、loginSource/skipRefreshToken |
| V2.0 |
2026-07-11 |
拆分为登录接口 + 信息同步接口;登录接口仅接收登录字段 |
| V2.1 |
2026-07-11 |
登录接口恢复全部字段(登录与信息同步可在同一请求完成);同步接口已存在入驻记录时仅允许更新审核状态 |
| V2.2 |
2026-07-15 |
新增 remarks 字段(登录+同步接口均支持),用于传递拒绝原因等备注信息 |