支付宝小程序插件 插件授权
插件授权的说明
与 第三方应用授权 场景下由 ISV 主动引导商户进行授权流程不同,小程序插件场景下的授权动作由商户在服务市场的订购行为触发。在商户订购后支付宝服务端会通过 Http 协议发送一个授权消息到三方应用所配置的插件应用,该授权主要为应用网关配送。请按照本文的要求正确处理该通知,处理完后请参见 插件后端开发 获取 app_auth_token。
插件授权消息说明
报文示例
注意:实际收到的是 POST 请求,参数在 Post Body 中。
ISV_GATEWAY_URL?****&Data={"headers":{"User-Agent":"Mozilla/4.0","Content-Type":"application/x-www-form-urlencoded; charset=UTF-8"},"data":{"notify_type":"open_app_auth_notify","charset":"UTF-8","biz_content":"{\\"notify_context\\":{\\"trigger\\":\\"appstore\\"},\\"detail\\":{\\"app_auth_token\\":\\"202004BB9d3901a7d39d4350a49fb00000000001\\",\\"user_id\\":\\"20881200000000002\\",\\"re_expires_in\\":32140800,\\"auth_time\\":1587573752655,\\"app_refresh_token\\":\\"202004BB81e2730b7ecc4295a551e00000000001\\",\\"auth_app_id\\":\\"20210000002\\",\\"app_id\\":\\"20190000000\\",\\"expires_in\\":31536000,\\"app_auth_code\\":\\"fa861f9d7032404bae53f54247000001\\"},\\"error\\":{}}","notify_time":"2020-04-23 00:42:32","sign":"****","auth_app_id":"2021000000000002","app_id":"2019000000000000","version":"1.0","sign_type":"RSA2","notify_id":"2020042300222004232009800000000007","status":"execute_auth"},"method":"POST","pid":"2088500000000002","url":"https://*****/gateway.do","timeout":16000}
协议参数说明
字段名 | 必填 | 字段说明 | 备注 |
---|---|---|---|
notify_id | 是 | 通知校验 ID,唯一标识一笔通知 | 相同 notify_id 称之为同一笔通知 |
notify_type | 是 | 通知类型 | 插件授权时的值固定为:open_app_auth_notify |
status | 否 | 业务状态 | 插件授权时值固定为:execute_auth |
notify_time | 是 | 通知发送时间 | UTC+8,格式为 yyyy-MM-dd HH:mm:ss。若为其它时区的服务器时间请自行转换 |
charset | 是 | 字符集 | 该字符集用于开发者对收到的报文进行验签使用 |
version | 是 | 版本号 | 目前固定为 1.0,商户仅应该识别 version 参数为空或者 version=1.0 的通知报文,其它应该拒绝 |
app_id | 是 | 接收通知的 app_id | 该 app_id 是本消息的接收方。 |
auth_app_id | 否 | 授权业务主体的 appId | 在插件授权场景下无此参数,开发者不用关心 |
sign | 是 | 签名 | 支付宝的签名值 |
sign_type | 是 | 签名类型 | 签名算法,目前支持 RSA2 签名算法。注意,该参数不参与验签。 |
biz_content | 是 | 该笔通知的业务内容 | 本次授权动作的详细信息。详细说明参见下文对于 biz_content 的说明 |
biz_content 说明
示例如下(为了展示方便,示例对 JSON 展示进行了格式化处理)
"data":
{"notify_type":"open_app_auth_notify",
"charset":"UTF-8",
"biz_content":"{
\\"notify_context\\":{\\"trigger\\":\\"appstore\\"},
\\"detail\\":{
\\"app_auth_token\\":\\"202004BB9d3901a7d39d4350a49fb00000000001\\",
\\"user_id\\":\\"20881200000000002\\",
\\"re_expires_in\\":32140800,
\\"auth_time\\":1587573752655,
\\"app_refresh_token\\":\\"202004BB81e2730b7ecc4295a551e00000000001\\",
\\"auth_app_id\\":\\"20210000002\\",
\\"app_id\\":\\"20190000000\\",
\\"expires_in\\":31536000,
\\"app_auth_code\\":\\"fa861f9d7032404bae53f54247000001\\"
},
\\"error\\":{}
}",
"notify_time":"2020-04-23 00:42:32",
"sign":"****","auth_app_id":"2021000000000002",
"app_id":"2019000000000000",
"version":"1.0",
"sign_type":"RSA2",
"notify_id":"2020042300222004232009800000000007",
"status":"execute_auth"
}
- detail:授权的详细信息
参数名 | 类型 | 最大长度 | 必填 | 描述 | 范例 |
---|---|---|---|---|---|
app_id | String | 32 | 是 | 被授权方应用 id,在插件授权场景下为插件的 ID。 | 2015072100001111 |
auth_app_id | String | 32 | 是 | 授权方的应用 id,在插件授权场景下指商户的 app_id。 | 2014072300002222 |
auth_time | String | 20 | 是 | 授权发生时间(自1970年1月1日零点算起的毫秒数),在插件授权场景下指商户订购时触发授权的时间。通知接受方需要根据auth_time 做令牌幂等。 |
1491746302568 |
app_auth_code | String | 32 | 是 | (兼容用)应用授权码,该参数提供给开发者用于兼容开发者页面授权的换码逻辑,新接入方推荐直接使用报文中的 app_auth_token 即可。 | 252a889e49af4e6cbtests17ae053X80 |
app_auth_token | String | 40 | 是 | 应用授权令牌。 | 201603BB6e8df928test473d9d4c94d57d5c0X00 |
expires_in | String | 16 | 是 | (废弃字段)目前应用授权访问令牌的有效期为永久(商户主动取消授权的情况下仍未将令牌置为无效)。刷新机制继续保留,开发者根据自己的存储安全性自行决定刷新时间。 | 123456 |
app_refresh_token | String | 40 | 是 | 刷新令牌。开发者可以通过调用 alipay.open.auth.token.app 接口进行 app_auth_token 的刷新。 | 201603BBdeb7d0ab1testbe898432a6490dfbX00 |
re_expires_in | String | 16 | 是 | (废弃字段)目前应用授权的刷新令牌有效期为永久(商户主动取消授权的情况下仍未将令牌置为无效)。 | 123456 |
user_id | String | 16 | 是 | 授权商户的 user_id。 | 授权商户的 user_id |
agent_app_id | String | 32 | 否 | 三方应用 id。插件授权的场景下有值,是插件归属的三方应用的 ID。 | 2014072300003333 |
- notfy_context:本次授权关联的一些上下文信息(开发者可以忽略)
参数名 | 类型 | 最大长度 | 必填 | 描述 | 范例 |
---|---|---|---|---|---|
trigger | String | 30 | 是 | 授权触发环境,插件订购场景下为 appstore,开发者无需关注 | appstore |
trigger_context | String | 1000 | 否 | trigger_contexttrigger 相关联的上下文,开发者无需关注 | 目前值为空 |
- error:授权过程中出现的异常情况(开发者可忽略,后续该字段会废弃)
参数名 | 类型 | 最大长度 | 必填 | 描述 | 范例 |
---|---|---|---|---|---|
appstore_online_pay | String | 20 | 否 | 特殊情况下的错误信息,大部分开发者无需关心。若 ISV 签约了“在线购买/口碑商品”产品且该产品的授权前置条件不满足则会有该值。 | LACK_FACE_TO_FACE |
appstore_online_pay 的可选取值如下:
错误码 | ISV | ISV 该怎么做 |
---|---|---|
FAIL | 系统错误,由于未知原因导致的系统错误 | 建议联系引导商户重新授权解决来解决 |
UNEXPECTED_CERTIFY_GRADE | 商户的个人认证等级不够 | 通知联系引导商户完成实名认证,再重新授权。注:个人用户完成个人实名认证,企业用户完成企业实名认证。 |
MERCHANT_DISCARD | 商户已经被清退;被清退的商户无法进行签约和发布商品 | - |
LACK_FACE_TO_FACE | 商户未签约当面付 | 建议联系引导商户完成口碑开店流程之后,再重新授权 |
开发者处理逻辑说明
根据授权主体进行授权令牌存储
授权主体表示授权令牌的参与方,区别于第三方应用授权的授权主体(授权关系建立在商户 app_id 和三方应用的 app_id 的二者),插件授权的授权主体新增了插件维度的信息,即:商户 app_id、 三方应用 app_id 和插件 ID 三者之间的授权关系。开发者保存插件授权令牌的情况下特别需要注意以下几点:
- 令牌存储(包括访问令牌和刷新令牌)需要有插件 ID 维度的信息,否则若三方应用同时开发多个插件,商户同时订购了这些插件,会存在不同插件的令牌相互覆盖的问题。
- 令牌存储(包括访问令牌和刷新令牌)需要有商户 app_id 维度的信息,不能用商户 uid,否则若商户名下多个小程序同时使用同一个插件的时候,会出现商户不同商户小程序的令牌相互覆盖的问题。
- 令牌存储需要存储 auth_time,用于保证授权令牌的最终一致性。
授权消息处理
1.消息处理 插件授权消息为老版本的开放平台消息,通过以下方式确认为插件授权消息(同时满足以下条件)。
- notify_type=open_app_auth_notify
- status=execute_auth
- agent_app_id 非空
2.授权消息的最终一致性
考虑下述原因,若 授权主体 一致,开发者需要根据 auth_time 保证令牌的最终一致性。
- 在极少的特殊操作情况下存在商户短时间进行多次授权的情况;
- 由于网络延迟原因开发者接受到授权消息的时间并不一定是授权发生。