第三方登录接口文档.md 10 KB

第三方登录接口文档

版本:V1.1
更新日期:2026-07-07
变更说明:扩展请求参数,支持传入用户名、药店名称、地址、联系人等用户信息


1. 概述

本接口用于第三方系统通过用户手机号换取登录 Token,实现免密登录。系统会自动查找或注册用户,返回访问令牌和刷新令牌。同时支持第三方系统传入用户详细信息(用户名、药店名称、地址、联系人等),由我方负责存储,第三方无需我方再次维护用户信息。

核心特性:

  • 按手机号自动查找或注册用户
  • 支持第三方传入用户名、药店信息等,自动保存到用户表
  • 不递增 tokenVersion,不踢出 PC 端已有会话
  • 新用户自动初始化 PLUS 会员

2. 接口信息

项目 说明
接口名称 外部系统换取小程序 Token
请求方式 POST
接口路径 /api/auth/external/miniapp-token
Content-Type application/json
字符编码 UTF-8

3. 鉴权方式

使用 API Key 鉴权,在请求头中传入:

X-Api-Key: {我方提供的API Key}

API Key 格式建议:32 位随机十六进制字符串(大小写字母 + 数字)。
参考示例:a3f8c21e67b94d0e5f1a6c8d3b9e2071

⚠️ 请妥善保管 API Key,不要泄露到前端代码或客户端。请在后端服务中调用此接口。


4. 请求参数

4.1 请求头(Headers)

参数名 类型 必填 说明
X-Api-Key String 接口鉴权密钥
Content-Type String 固定值 application/json

4.2 请求体(Body)

基础字段

参数名 类型 必填 说明
phone String 用户手机号
inviteCode String 邀请码(仅新用户注册时生效)

用户信息字段(第三方传入,自动保存)

参数名 类型 必填 说明 对应我方字段
username String 用户名(保存到 nickname 字段,优先级高于 nickname) nickname
nickname String 昵称(不传则使用 username,再不传则按手机号生成) 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

💡 字段更新规则

  • 新用户会写入所有传入字段
  • 已存在用户仅更新非空字段(不会清空已有数据)

💡 nickname 优先级username > nickname > 手机号生成(如 用户8000

💡 建议:第三方每次调用时传入最新的用户信息,我方会自动同步更新,无需额外维护。

4.3 请求示例

最简请求(仅必填字段)

{
  "phone": "13800138000"
}

完整请求(含用户信息)

{
  "phone": "13800138000",
  "inviteCode": "ABC123",
  "username": "yaohuigou001",
  "pharmacyName": "北京同仁堂大药房",
  "province": "北京市",
  "city": "北京市",
  "district": "朝阳区",
  "pharmacyAddress": "建国路88号",
  "contactPerson": "张三",
  "contactPhone": "13800138000",
  "businessLicenseNo": "91110105MA12345678"
}

5. 响应参数

5.1 通用响应结构

{
  "code": 200,
  "message": "success",
  "data": { }
}
字段 类型 说明
code int 状态码,200 表示成功
message String 提示信息
data Object 登录响应数据

5.2 data 字段

参数名 类型 说明
userId String 用户ID(字符串,避免JS大数精度丢失)
accessToken String 访问令牌
refreshToken String 刷新令牌
expiresIn Long accessToken有效期(秒),默认7200
newUser Boolean 是否为新注册用户
needBindPhone Boolean 始终返回false
role String 固定值"USER"
userInfo Object 用户基本信息

5.3 userInfo 字段说明

参数名 类型 说明
id String 用户ID
phone String 手机号
nickname String 昵称(即第三方传入的 username 或 nickname)
avatar String 头像 URL
wechatBound Boolean 是否已绑定微信
loginSource String 登录来源,"MINIAPP" 表示小程序
membershipLevel String 会员等级代码
membershipLevelName String 会员等级名称
createTime String 注册时间

5.4 响应示例

{
  "code": 200,
  "message": "success",
  "data": {
    "userId": "1234567890123456789",
    "accessToken": "eyJhbGciOiJIUzI1NiJ9...",
    "refreshToken": "eyJhbGciOiJIUzI1NiJ9...",
    "expiresIn": 7200,
    "newUser": false,
    "needBindPhone": false,
    "role": "USER",
    "userInfo": {
      "id": "1234567890123456789",
      "phone": "138****8000",
      "nickname": "yaohuigou001",
      "avatar": null,
      "wechatBound": false,
      "loginSource": "MINIAPP",
      "membershipLevel": "PLUS",
      "membershipLevelName": "PLUS会员",
      "createTime": "2025-01-01T12:00:00"
    }
  }
}

6. 错误码

错误码 说明 处理建议
200 成功
401 API Key 无效或缺失 检查X-Api-Key请求头
400 参数校验失败 检查phone是否为空
500 服务器内部错误 重试,持续失败联系我方

7. Token 使用说明

7.1 携带 Token

后续所有业务接口请求需在请求头中携带 accessToken:

Authorization: Bearer {accessToken}

7.2 Token 刷新

accessToken 过期后,使用 refreshToken 换取新 Token:

POST /api/auth/refresh
Content-Type: application/json

{ "refreshToken": "{refreshToken}" }

刷新后旧 refreshToken 立即失效(Token 旋转机制)。

7.3 心跳保活

建议客户端定时调用心跳接口,保持登录状态:

POST /api/auth/heartbeat
Authorization: Bearer {currentAccessToken}

建议间隔 = accessToken有效期 × 80%,约5760秒。


8. 注意事项

# 说明
1 PC端严格单设备,小程序与PC互不干扰,同一账号可同时登录
2 手机号未注册时自动创建账号并初始化PLUS会员
3 inviteCode仅新用户注册时生效
4 API Key请在后端调用,勿暴露到客户端
5 accessToken默认2小时,refreshToken默认7天
6 每次刷新后旧refreshToken立即作废,请保存最新的
7 用户信息字段(username、药店信息等)每次调用都会同步更新,建议传入最新数据
8 username 会保存到我方的 nickname 字段,不需要额外维护用户名表

9. 调用示例

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",
    "username": "yaohuigou001",
    "pharmacyName": "北京同仁堂大药房",
    "province": "北京市",
    "city": "北京市",
    "district": "朝阳区",
    "pharmacyAddress": "建国路88号",
    "contactPerson": "张三",
    "contactPhone": "13800138000",
    "businessLicenseNo": "91110105MA12345678"
  }'

Java (OkHttp)

OkHttpClient client = new OkHttpClient();

String json = "{"
    + "\"phone\": \"13800138000\","
    + "\"username\": \"yaohuigou001\","
    + "\"pharmacyName\": \"北京同仁堂大药房\""
    + "}";

RequestBody body = RequestBody.create(json, MediaType.parse("application/json"));
Request request = new Request.Builder()
    .url("https://your-domain.com/api/auth/external/miniapp-token")
    .post(body)
    .addHeader("X-Api-Key", "your-api-key-here")
    .addHeader("Content-Type", "application/json")
    .build();

try (Response response = client.newCall(request).execute()) {
    System.out.println(response.body().string());
}

Python (requests)

import requests

url = "https://your-domain.com/api/auth/external/miniapp-token"
headers = {
    "X-Api-Key": "your-api-key-here",
    "Content-Type": "application/json"
}
data = {
    "phone": "13800138000",
    "username": "yaohuigou001",
    "pharmacyName": "北京同仁堂大药房",
    "province": "北京市",
    "city": "北京市",
    "district": "朝阳区"
}

response = requests.post(url, json=data, headers=headers)
print(response.json())

10. 字段映射表

第三方传入字段与我方数据库字段的对应关系:

第三方传入字段 我方数据库字段 我方实体字段 说明
phone phone phone 手机号(必填)
username nickname nickname 用户名(保存到 nickname)
nickname nickname nickname 昵称(优先级低于 username)
pharmacyName pharmacy_name pharmacyName 药店名称
province province province
city city city
district district district
pharmacyAddress pharmacy_address pharmacyAddress 药店详细地址
contactPerson contact_person contactPerson 联系人
contactPhone contact_phone contactPhone 联系电话
businessLicenseNo business_license_no businessLicenseNo 营业执照号

11. 联系方式

如有问题,请联系我方技术支持。


12. 变更记录

版本 日期 变更内容
V1.0 2026-07-07 初始版本:基础登录接口
V1.1 2026-07-07 扩展请求参数:支持传入用户名、药店信息等,自动保存到用户表