大白菜聚合登录

开发文档

三个接口,五分钟接入聚合登录

1 协议规则

请求方式GET
传输协议HTTPS(推荐)/ HTTP
数据格式JSON
字符编码UTF-8
接口根地址https://connect.boshou.me/connect
所有接口都必须由你的服务器调用。appkey 是签名密钥,一旦放到前端就等于公开。

2 接入流程

你的服务器 ──① 请求 /connect/login──▶ 本站
                                       │ 本站向上游取授权地址
                                       ▼
你的网站 ◀── 返回 url ─────────────────┘
   │ ② 把用户浏览器跳到 url
   ▼
第三方(QQ / 微信 …)──③ 用户授权完成 ──▶ 跳回你配置的 redirect_uri?type=qq&code=xxxx
   │
   ▼
你的服务器 ──④ 用 code 请求 /connect/callback──▶ 本站
                                                   ▼
                                   返回 social_uid / nickname / faceimg …

拿到 social_uid 后,在你的用户表里按它查找或创建用户即可完成登录。

3 签名规则

  1. 除 sign 外的所有参数,按参数名 ASCII 升序排列
  2. 拼成 k1=v1&k2=v2&…(原始值,不做 urlencode)
  3. 末尾追加 &key={appkey}
  4. 对整串取 sha256,得到小写十六进制即为 sign
  5. 请求必须携带 timestamp,与服务端相差超过 300 秒会被拒绝
服务端用 hash_equals 做恒定时间比对,你那边排序时注意大小写与数字的顺序(ASCII 序)。

4 获取授权地址

GET https://connect.boshou.me/connect/login
参数类型必填说明
appid string 是 你的应用 ID
type string 是 登录方式,见下方对照表
redirect_uri string 是 登录完成后跳回的地址,必须命中应用配置的回调域名白名单
timestamp int 是 秒级时间戳,与服务端相差超过 300 秒会被拒绝
sign string 是 请求签名,算法见「签名规则」
RESPONSE{
  "code": 0,
  "msg": "succ",
  "type": "qq",
  "url": "https://graph.qq.com/oauth2.0/show?...",
  "qrcode": "https://…"
}

qrcode 仅微信和支付宝返回,是扫码登录地址,可用于 PC 端扫码。

5 换取用户信息

GET https://connect.boshou.me/connect/callback
参数类型必填说明
appid string 是 你的应用 ID
type string 是 登录方式,需与获取授权地址时一致
code string 是 第三方跳回你网站时带上的授权码
timestamp int 是 秒级时间戳
sign string 是 请求签名
授权码是一次性的,有效期 5 分钟,用完即失效。同一个 code 重复请求会返回 1008。
RESPONSE{
  "code": 0,
  "msg": "succ",
  "type": "qq",
  "social_uid": "AD3F5033279C8187CBCBB29235D5F827",
  "access_token": "89DC9691E274D6B596FFCB8D43368234",
  "faceimg": "https://thirdqq.qlogo.cn/g?b=oidb&k=…",
  "nickname": "大白",
  "location": "成都市",
  "gender": "男",
  "ip": "1.12.3.40"
}
字段类型说明
social_uid string 第三方账号唯一标识 —— 用它来识别用户,也是额度计数的依据
nickname string 用户昵称
faceimg string 用户头像地址
access_token string 第三方返回的令牌
gender string 性别
location string 所在地(仅支付宝 / 微信返回)
ip string 用户登录 IP

6 复查用户信息

用户登录之后的任意时间,都可以用 social_uid 再次查询其信息(例如昵称、头像有更新时)。

GET https://connect.boshou.me/connect/query?appid=…&type=qq&social_uid=…&timestamp=…&sign=…

返回字段与 /callback 完全一致。

7 错误码

code含义说明
0 成功 ok
2 未完成登录 用户还没在第三方完成授权,稍后重试即可
1001 参数缺失 必填参数没传或为空
1002 签名错误 sign 校验不通过,检查参数排序与 appkey
1003 时间戳过期 与服务端时间相差超过 300 秒,校准服务器时间
1004 应用不存在 appid 错误,或应用已停用 / 已删除
1005 套餐已过期 续费后即可恢复
1006 登录方式不可用 该登录方式不在当前套餐允许范围内
1007 账号额度已用尽 新账号无法继续登录,续费或升级套餐
1008 授权码无效 code 已过期或已被使用(授权码一次性)
1009 上游暂不可用 第三方服务异常,稍后重试
1010 请求过于频繁 触发接口限流,降低频率后重试

8 示例代码

 $value) {
        $parts[] = $key . '=' . $value;
    }

    return hash('sha256', implode('&', $parts) . '&key=' . APPKEY);
}

/** 带上签名发起请求 */
function api(string $action, array $params): array
{
    $params['appid']     = APPID;
    $params['timestamp'] = time();
    $params['sign']      = sign($params);

    $url = API_BASE . '/' . $action . '?' . http_build_query($params);
    $raw = file_get_contents($url, false, stream_context_create([
        'http' => ['timeout' => 10],
    ]));

    return json_decode((string) $raw, true) ?: ['code' => -1, 'msg' => '接口无响应'];
}

// ───────── 第一步:拿到第三方授权地址,把用户送过去 ─────────
function startLogin(string $type, string $redirectUri): void
{
    $res = api('login', [
        'type'         => $type,
        'redirect_uri' => $redirectUri,
    ]);

    if ((int) $res['code'] !== 0) {
        exit('获取登录地址失败:' . $res['msg']);
    }

    // 微信 / 支付宝还会返回 qrcode(扫码地址),可用于 PC 扫码登录
    header('Location: ' . $res['url']);
    exit;
}

// ───────── 第二步:用户从第三方跳回来,用 code 换用户信息 ─────────
function handleCallback(string $type, string $code): array
{
    $res = api('callback', ['type' => $type, 'code' => $code]);

    if ((int) $res['code'] === 2) {
        // 用户还没完成授权(比如扫码扫到一半),稍后重试即可
        exit('正在登录中,请稍候刷新…');
    }

    if ((int) $res['code'] !== 0) {
        exit('登录失败:' . $res['msg']);
    }

    // social_uid 是第三方账号的唯一标识,用它在你自己的库里找/建用户
    return [
        'social_uid' => $res['social_uid'],
        'nickname'   => $res['nickname'],
        'avatar'     => $res['faceimg'],
        'gender'     => $res['gender'],
    ];
}

// ───────── 第三步(可选):事后复查用户信息 ─────────
function queryUser(string $type, string $socialUid): array
{
    return api('query', ['type' => $type, 'social_uid' => $socialUid]);
}
appid 已经帮你填好了;appkey 是占位符,请到「我的应用」里复制。
/**
 * 聚合登录接入示例(Node.js)
 *
 * 必须跑在你的服务端。appkey 是签名密钥,不要下发到浏览器。
 */

const crypto = require('crypto');

const APPID    = '你的 appid';
const APPKEY   = '你的 appkey';
const API_BASE = 'https://connect.boshou.me/connect';

/** 签名:除 sign 外按参数名升序拼接,末尾追加 &key=appkey,取 sha256 */
function sign(params) {
    const parts = Object.keys(params)
        .filter((k) => k !== 'sign')
        .sort()
        .map((k) => `${k}=${params[k]}`);

    return crypto.createHash('sha256')
        .update(parts.join('&') + '&key=' + APPKEY)
        .digest('hex');
}

/** 带上签名发起请求 */
async function api(action, params) {
    const all = { ...params, appid: APPID, timestamp: Math.floor(Date.now() / 1000) };
    all.sign = sign(all);

    const url = `${API_BASE}/${action}?` + new URLSearchParams(all).toString();
    const res = await fetch(url);
    return res.json();
}

// 第一步:拿到第三方授权地址,重定向用户
async function startLogin(type, redirectUri) {
    const res = await api('login', { type, redirect_uri: redirectUri });

    if (res.code !== 0) {
        throw new Error('获取登录地址失败:' + res.msg);
    }

    // 微信 / 支付宝还会有 res.qrcode(扫码地址)
    return res.url;
}

// 第二步:用户跳回来后,用 code 换用户信息
async function handleCallback(type, code) {
    const res = await api('callback', { type, code });

    if (res.code === 2) {
        throw new Error('用户尚未完成授权,请稍后重试');
    }
    if (res.code !== 0) {
        throw new Error('登录失败:' + res.msg);
    }

    return {
        socialUid: res.social_uid,
        nickname: res.nickname,
        avatar: res.faceimg,
    };
}

// 第三步(可选):事后复查
function queryUser(type, socialUid) {
    return api('query', { type, social_uid: socialUid });
}

9 常见问题

返回 1002 签名错误怎么办?
先确认参数按参数名 ASCII 升序排列、值没有做 urlencode、末尾是 &key=你的appkey。注意排序要区分大小写:大写字母排在小写之前。
返回 1003 时间戳过期?
服务器时间不准。校准一下系统时间(Linux 下可执行 ntpdate 或用 systemd-timesyncd),允许的偏差是 ±300 秒。
用户扫了码但一直停在「正在登录中」?
说明用户还没在第三方完成授权,接口会返回 code=2。这在扫码登录场景很正常,隔一两秒重试即可,不要当失败处理。
同一个用户重复登录会重复占用额度吗?
不会。额度按「不同的第三方账号」计数,同一个 QQ 号反复登录只算一个账号,而且在你名下的多个应用之间也是共用的。
额度用完了老用户还能登录吗?
可以。额度用尽只拦截「新账号」,已经登录过的用户不受影响,续费或升级后新账号立刻恢复。
redirect_uri 必须命中白名单吗?
必须。应用配置里的回调域名白名单是防止授权码被劫持的关键,只填主域名即可,子域名会自动放行。