开放授权登录

接口说明

第三方商户可以通过开放授权登录地址,把商户自己的用户标识和盟主平台用户建立授权关系。用户完成登录或免授权注册后,页面会跳转到商户传入的 callback 地址。

请求地址:

https://nu.zmengzhu.com/open/authorize/login

请求方式:

GET

注意:本文只适用于 /open/authorize/login 授权跳转。调用 api.zmengzhu.com/business/v1/* 业务 API 时,请使用业务 API 签名机制。

请求参数

必填参数

参数名 类型 必选 说明
appid string 商户应用 ID,由盟主平台提供
nickname string 第三方用户昵称
avatar string 第三方用户头像 URL
third_uid string 第三方平台用户唯一标识
callback string 授权成功后的回跳地址,需要 URL encode;播放页需要种 Cookie 时,请传完整播放页 URL
sign string 请求签名,32 位 MD5 字符串

常用可选参数

参数名 类型 必选 说明
expire_time int 授权链接过期时间,10 位秒级 Unix 时间戳;当前时间大于该值时,接口返回“该地址已过期请重新获取”
expired int 历史示例里常见的有效期秒数字段;当前入口不按该字段做过期校验,只作为普通 query 参数参与签名
is_embed int 是否嵌入页面;1 表示跳过微信环境下的盟主公众号 OAuth
is_other_auth int 是否第三方免授权场景;和 is_embed=1 同时使用时,回跳地址会追加 atom 登录态

is_embed 和 is_other_auth 场景建议

is_embedis_other_auth 用于控制授权过程中是否触发微信 OAuth,以及是否把免授权登录态回传给商户页面。

场景 is_embed is_other_auth 说明
普通浏览器或 PC 打开授权链接 0 0 非微信环境不会进入公众号 OAuth,注册或登录后直接回跳
微信 H5 内,并且希望走盟主公众号 OAuth 0 0 微信环境会进入盟主公众号 OAuth,依赖公众号网页授权配置
微信小程序 web-view、第三方 App web-view、iframe 嵌入页 1 1 推荐。跳过公众号 OAuth,用 atom 参数把登录态回传给业务页;完整播放页 callback 会先种 Cookie 再回跳
嵌入页但依赖 Cookie 登录态 1 0 会跳过公众号 OAuth,但不会回传 atom;只适合 Cookie 一定可写且回跳页能读到的场景
is_embed=0is_other_auth=1 0 1 不推荐。微信环境仍会先进入公众号 OAuth,且不会回传 atom

微信小程序 web-view 的 UA 通常包含 MicroMessenger。如果不传 is_embed=1,接口会按微信环境处理并进入盟主公众号 OAuth,可能出现微信弹窗:

无法获取用户身份
登录的微信号未绑定为公众号的网页开发者,无法使用 OAuth 授权登录获取用户身份

小程序 web-view 场景建议传:

is_embed=1&is_other_auth=1

此时授权成功后,接口会在 callback 地址后追加:

atom=base64("sid=xxx")&mzuid=用户uid&i=用户uid

商户页面可通过 atom 识别用户登录态,不需要再触发微信 OAuth。

如果 callback 是完整播放页 URL,且路径符合 /play/{ticket_id},例如:

https://v.zmengzhu.com/play/42801569

授权成功后会先跳到同播放域下的 /wap/channel/atomAuthPlayMZSID Cookie,再跳回播放页。这样既保留 URL 中的 atom,也兼容需要通过 Cookie 识别用户身份的播放页接口。

如果 callback 是相对路径,例如 /play/42801569,或不是 /play/{ticket_id} 播放页路径,则保持原有逻辑,直接回跳,不会自动经过 atomAuthPlay

callback 说明

callback 是授权成功后的回跳地址。

播放页需要种 Cookie 时,建议传完整播放页 URL:

callback=https://v.zmengzhu.com/play/42801569

并整体 URL encode 后参与签名:

callback=https%3A%2F%2Fv.zmengzhu.com%2Fplay%2F42801569

如果传相对路径:

callback=/play/42801569

授权入口无法知道实际播放域名,会保持原有逻辑直接回跳,不会自动经过 /wap/channel/atomAuthPlay 种 Cookie。

不要把 callback 里的 ?xxx=... 当成外层请求参数。

签名规则

第一步:准备请求参数

准备除 sign 外的所有请求参数。

示例参数:

{
  "appid": "10000001",
  "avatar": "https://example.com/avatar.png",
  "callback": "https://v.zmengzhu.com/play/42801569",
  "expired": 60,
  "is_embed": 1,
  "is_other_auth": 1,
  "nickname": "微信用户",
  "third_uid": "user-001"
}

示例密钥:

secret

示例中保留 expired 是为了对应历史示例并保持结果固定可复算。如果需要真正限制链接过期时间,请传 expire_time,并把 expire_time 一起放入 query 后重新计算签名。

第二步:生成 queryString

使用标准 URL query 规则生成 queryString,参数值必须先 URL encode。

执行结果:

appid=10000001&avatar=https%3A%2F%2Fexample.com%2Favatar.png&callback=https%3A%2F%2Fv.zmengzhu.com%2Fplay%2F42801569&expired=60&is_embed=1&is_other_auth=1&nickname=%E5%BE%AE%E4%BF%A1%E7%94%A8%E6%88%B7&third_uid=user-001

注意:avatarcallbacknickname 都已经 URL encode。

第三步:生成 urlSuffix

urlSuffix 是去掉协议后的完整请求地址:

域名 + 路径 + ? + queryString

执行结果:

nu.zmengzhu.com/open/authorize/login?appid=10000001&avatar=https%3A%2F%2Fexample.com%2Favatar.png&callback=https%3A%2F%2Fv.zmengzhu.com%2Fplay%2F42801569&expired=60&is_embed=1&is_other_auth=1&nickname=%E5%BE%AE%E4%BF%A1%E7%94%A8%E6%88%B7&third_uid=user-001

第四步:生成待签名字符串

urlSuffix + secret_key

执行结果:

nu.zmengzhu.com/open/authorize/login?appid=10000001&avatar=https%3A%2F%2Fexample.com%2Favatar.png&callback=https%3A%2F%2Fv.zmengzhu.com%2Fplay%2F42801569&expired=60&is_embed=1&is_other_auth=1&nickname=%E5%BE%AE%E4%BF%A1%E7%94%A8%E6%88%B7&third_uid=user-001secret

第五步:计算 sign

对待签名字符串做 MD5:

md5(signSource)

得到:

86aff90feced901f9c3aae87c077eb0b

第六步:拼接最终请求 URL

最终请求 URL 使用同一个 queryString,在末尾追加 &sign=签名值

https://nu.zmengzhu.com/open/authorize/login?appid=10000001&avatar=https%3A%2F%2Fexample.com%2Favatar.png&callback=https%3A%2F%2Fv.zmengzhu.com%2Fplay%2F42801569&expired=60&is_embed=1&is_other_auth=1&nickname=%E5%BE%AE%E4%BF%A1%E7%94%A8%E6%88%B7&third_uid=user-001&sign=86aff90feced901f9c3aae87c077eb0b

PHP 示例

<?php

$secretKey = 'secret';

$params = [
    'appid' => '10000001',
    'avatar' => 'https://example.com/avatar.png',
    'callback' => 'https://v.zmengzhu.com/play/42801569',
    'expired' => 60,
    'is_embed' => 1,
    'is_other_auth' => 1,
    'nickname' => '微信用户',
    'third_uid' => 'user-001',
];

$queryString = http_build_query($params);
$urlSuffix = 'nu.zmengzhu.com/open/authorize/login?' . $queryString;
$sign = md5($urlSuffix . $secretKey);
$url = 'https://' . $urlSuffix . '&sign=' . $sign;

echo "queryString:\n" . $queryString . "\n\n";
echo "urlSuffix:\n" . $urlSuffix . "\n\n";
echo "signSource:\n" . $urlSuffix . $secretKey . "\n\n";
echo "sign:\n" . $sign . "\n\n";
echo "url:\n" . $url . "\n";

输出结果:

queryString:
appid=10000001&avatar=https%3A%2F%2Fexample.com%2Favatar.png&callback=https%3A%2F%2Fv.zmengzhu.com%2Fplay%2F42801569&expired=60&is_embed=1&is_other_auth=1&nickname=%E5%BE%AE%E4%BF%A1%E7%94%A8%E6%88%B7&third_uid=user-001

urlSuffix:
nu.zmengzhu.com/open/authorize/login?appid=10000001&avatar=https%3A%2F%2Fexample.com%2Favatar.png&callback=https%3A%2F%2Fv.zmengzhu.com%2Fplay%2F42801569&expired=60&is_embed=1&is_other_auth=1&nickname=%E5%BE%AE%E4%BF%A1%E7%94%A8%E6%88%B7&third_uid=user-001

signSource:
nu.zmengzhu.com/open/authorize/login?appid=10000001&avatar=https%3A%2F%2Fexample.com%2Favatar.png&callback=https%3A%2F%2Fv.zmengzhu.com%2Fplay%2F42801569&expired=60&is_embed=1&is_other_auth=1&nickname=%E5%BE%AE%E4%BF%A1%E7%94%A8%E6%88%B7&third_uid=user-001secret

sign:
86aff90feced901f9c3aae87c077eb0b

url:
https://nu.zmengzhu.com/open/authorize/login?appid=10000001&avatar=https%3A%2F%2Fexample.com%2Favatar.png&callback=https%3A%2F%2Fv.zmengzhu.com%2Fplay%2F42801569&expired=60&is_embed=1&is_other_auth=1&nickname=%E5%BE%AE%E4%BF%A1%E7%94%A8%E6%88%B7&third_uid=user-001&sign=86aff90feced901f9c3aae87c077eb0b

常见问题

sign 是否参与签名

不参与。先使用除 sign 外的参数生成签名,再把 sign 追加到最终 URL。

签名时是否包含协议

不包含。待签名内容从域名开始:

nu.zmengzhu.com/open/authorize/login?...

最终请求 URL 才加上 https://

参数是否需要排序

当前规则以最终 URL 的 query 内容为准。建议固定参数顺序,签名时和最终请求时使用同一个 queryString,不要在签名后重新组装或调整参数顺序。

参数值是否需要 URL encode

需要。avatarcallbacknickname 都是 query 参数值,必须先 URL encode 后再参与签名。

错误示例:

avatar=https://example.com/avatar.png

正确示例:

avatar=https%3A%2F%2Fexample.com%2Favatar.png

callback 应该怎么传

callback 要整体 URL encode。播放页需要种 Cookie 时,请传完整播放页 URL。

例如:

https://v.zmengzhu.com/play/42801569

编码后:

https%3A%2F%2Fv.zmengzhu.com%2Fplay%2F42801569

为什么传相对 callback 会跳到 nu.zmengzhu.com

因为相对路径没有域名,浏览器会按当前授权页域名解析。授权页域名是 nu.zmengzhu.com,所以相对路径会回跳到 nu.zmengzhu.com 下。

如果要回跳到商户自己的域名,请传完整 URL,并整体 URL encode。

微信小程序里出现“无法获取用户身份”怎么办

小程序 web-view 场景建议传:

is_embed=1&is_other_auth=1

这样可以跳过盟主公众号 OAuth,并通过回跳地址里的 atom 参数识别登录态。