SPI 三方服务接入指南

背景介绍


随着开放生态的逐步发展,合作商家的业务不断拓展,对于服务的多样性、效率及体验都有了更高的要求。

借助 SPI(Service Provider Interface,外部服务商接口),支付宝开放平台调用第三方系统服务提供的接口,实现和不同软件服务商的协同,扩展更多的生态场景,丰富开放平台提供的产品能力。


整体流程

SPI 的接入流程如下图所示:

22.png支付宝:

  1. 在后台设置 SPI 的相关规范(如调用类型、请求方法、参数和错误码等);
  2. 将若干个 SPI 组合成实现具体业务功能的产品功能包;
  3. 将功能包以全面开放(外部服务商可以自助添加)或者定向开放(仅对特定目标服务商可见)的形式发布;
  4. 待第三方系统服务商完成相关 SPI 的开发并成功发布后,即可调用第三方系统服务商提供的 SPI。


第三方系统服务商:

根据支付宝 SPI 的相关规范完成 SPI 的开发,按照如下步骤完成 SPI 功能包的添加并成功发布服务。


第一步:创建应用并获取 APPID

要在您的应用中接入支付宝开放平台中的能力,您需要先登录支付宝开放平台(open.alipay.com),在开发者中心中创建登记您的应用,并提交审核,审核通过后会为您生成应用唯一标识(APPID),并且可以申请开通开放产品使用权限。通过 APPID 您的应用才能调用开放产品的接口能力。需要详细了解开放平台创建应用步骤请参考《开放平台应用创建指南》


第二步:配置密钥

为了保证交易双方(商户和支付宝)的身份和数据安全,开发者在调用接口前,需要配置双方密钥,对交易数据进行双方校验。密钥包含应用私钥(APP_PRIVATE_KEY)和应用公钥(APP_PUBLIC_KEY)。生成密钥后,开发者需要在开放平台开发者中心进行密钥配置,配置完成后可以获取支付宝公钥(ALIPAY_PUBLIC_KEY),配置的详细步骤请参考《配置应用环境》。您还可以通过观看 快速签名教程 学习密钥的配置。密钥的配置旨在对交易数据进行双方校验。具体流程如下图所示:


  • 应用公钥(商户自身的 RSA/RSA2 公钥): 支付宝使用该公钥验证该交易是商户发起。
  • 支付宝公钥(支付宝的 RSA/RSA2 公钥):商户使用该公钥验证该结果是支付宝返回的。


说明

支付宝开放平台 SDK 封装了签名和验签过程,只需配置账号及密钥参数,建议开发者使用。开发者还可以通过自助排查流程验签教程自助排查配置应用过程中遇到的问题。


第三步:添加 SPI 功能包

实现 SPI 服务时,第三方系统服务商(ISV)需先关联相关产品,关联产品的入口有两个:

  • 应用详情页挂载功能包的列表页
  • 能力中心的列表页获取


1. 应用详情页关联SPI产品

1.1 添加功能包

此处添加功能包适用于全面开放的功能包。如果是定向功能包,需要由功能包的提供方在支付宝后台进行定向挂载。

注:目前 SPI 功能包暂时都是定向开放。image.png

1.2 实现功能包中的SPI接口

image.png

1.3 点击接入

image.png


2. 能力中心关联 SPI 产品

能力中心包括获取能力和发布能力两部分功能:

  • 获取能力是指开发者作为能力使用方来获取并使用功能包(OPENAPI 等开放接口封装的产品)
  • 发布能力是指开发者作为能力提供方来实现并发布功能包(SPI 产品)


2.1 能力中心入口

image.png


2.2 能力获取入口

image.png


2.3 选择需要实现的能力

image.png


2.4 绑定应用

image.png


2.5 开发SPI能力

image.png


1.6 点击接入

image.png


第四步:SPI 接口实现

1. 开发管理

1.1 查看场景的基本信息以及详细文档

1.2 进行能力发布的管理

即三方实现的功能包的上线及下线,当所有官方定义的 SPI 列表中必须实现的接口都是“已上线”状态时,可进行能力的上线申请。能力上线后可被官方集成使用,如有异常可进行下线处理,如需再次上线请重新申请。如要停止能力提供,请进行下线申请。

image.png

1.3 进行三方实现的接口的生命周期管理

接口状态

可执行操作

未接入接口接入

开发中

详情,提交审核,修改

审核中

详情,撤销审核

待发布

详情,发布

已驳回

详情,提交审核,修改

已上线

详情,升级


2. 接口接入

2.1 引导流程

image.png


2.2 服务基础配置

image.png


3. 在线测试

不满足以下条件的需要给出错误提示:

  • 对于需要签约的功能包没有完成签约
  • 功能包绑定的应用必须是上线状态
  • 功能包需要完全的相关配置项没有填写

image.png


4. 接口审核

SPI 接口联调通过以后可以发起接口审核。

image.png


5. 能力发布上线审核

当所有 SPI 接口审核通过后,可进行能力上线发布审核。

image.png


第五步 服务端接口开发

1. 下载服务端SDK

为了帮助 ISV 开发SPI接口,我们提供了开放平台服务端 SDK,包含 JAVA、PHP、Python、NodeJS 和 .NET 等语言的版本,封装了签名、验签逻辑。请先下载对应语言版本的 SDK 并引入您的开发工程。

各语言版本服务端 SDK 详细使用说明,请参考《服务端 SDK 使用说明


2. 通信规范

2.1 协议规则

外部商户接入支付宝开放平台出口网关,提供的服务必须满足以下规范:

网络传输协议

支持 http、https

数据提交方法

支持 GET、POST

Content-Type

application/x-www-form-urlencoded

响应报文格式

JSON

签名算法

支持 RSA、RSA2

字符集

支持 GBK、UTF-8

2.2 请求报文格式

Header 参数

由 SPI 接口文档中的 Header 参数定义,Header中的key具有固定前缀"x_"。


Query 参数

字段类型

字段

类型

是否必填

描述

示例值

系统字段(固定)

method

String

接口

alipay.xxx

charset

String

字符集

UTF-8

version

String

版本号,默认1.0

1.0

biz_app_id

String

商户app_id

2018XXX123

invoke_app_id

String

调用方app_id

2018XXX321

utc_timestamp

String

时间戳(秒)

1546077067

sign_type

String

签名算法,支持RSA、RSA2

RSA2

sign

String

签名值

***

业务字段(自定义)

由 SPI 接口文档中的 Query 参数定义,所有业务字段与系统字段处于同一层级。


Body 参数

由 SPI 接口文档中的 Body 参数定义,Content-Type为:application/x-www-form-urlencoded


2.3 响应报文格式


响应参数定义


字段

类型

是否必填

描述

示例值

response

String

JSON格式字符串

{"code":"10000","msg":"success","key_1":"Value1"}

sign

String

签名值

TqnBnkILs86FJWRqWWZptqIpSKLIp2vnwod177h7GLyWuLhzgRHpXgXd8GoD4flyHrHBTycQdiUjWw6VqCE5rYHrJU3iYqI1e0MLlhCb

app_cert_sn

String

应用证书编号。如果应用在开放门户升级了证书模式,则商户返回报文加签需要使用证书进行加签,同时响应报文需要返回证书编号字段:app_cert_sn

6cd4ee7e4f31c1adba2380cc65da4a3a


response 定义


字段

类型

是否必填

描述

示例值

code

String

错误码只有两种:成功-10000;失败-40004

40004

msg

String

错误描述:成功-Success;失败-Business Failed

Business Failed

sub_code

String

业务错误码,在业务失败的情况下返回,与 SPI 接口文档里的“业务错误码”保持一致

INVALID_PARAMS

sub_msg

String

业务错误描述,在业务失败的情况下返回,与 SPI 接口文档里的“业务错误码”保持一致

无效参数

业务字段(自定义)

由 SPI 接口文档中的响应参数定义

2.4 响应报文示例

  • 成功报文示例
{
    "response":{
        "code":"10000",
        "msg":"Success",
        "name":"lisi"
    },
    "sign":"TqnBnkILs86FJWRqWWZptqIpSKLIp2vnwod177h7GLyWuLhzgRHpXgXd8GoD4flyHrHBTycQdiUjWw6VqCE5rYHrJU3iYqI1e0MLlhCb"
}


  • 成功报文示例(证书模式)
{
    "response":{
        "code":"10000",
        "msg":"Success",
        "name":"lisi"
    },
    "app_cert_sn":"6cd4ee7e4f31c1adba2380cc65da4a3a",
    "sign":"TqnBnkILs86FJWRqWWZptqIpSKLIp2vnwod177h7GLyWuLhzgRHpXgXd8GoD4flyHrHBTycQdiUjWw6VqCE5rYHrJU3iYqI1e0MLlhCb"
}


  • 失败报文示例
{
    "response":{
        "code":"40004",
        "msg":"Business Failed",
        "sub_code":"INVALID_PARAMS",
        "sub_msg":"无效参数"
    },
    "sign":"TqnBnkILs86FJWRqWWZptqIpSKLIp2vnwod177h7GLyWuLhzgRHpXgXd8GoD4flyHrHBTycQdiUjWw6VqCE5rYHrJU3iYqI1e0MLlhCb"
}


  • 失败报文示例(证书模式)
{
    "response":{
        "code":"40004",
        "msg":"Business Failed",
        "sub_code":"INVALID_PARAMS",
        "sub_msg":"无效参数"
    },
    "app_cert_sn":"6cd4ee7e4f31c1adba2380cc65da4a3a",
    "sign":"TqnBnkILs86FJWRqWWZptqIpSKLIp2vnwod177h7GLyWuLhzgRHpXgXd8GoD4flyHrHBTycQdiUjWw6VqCE5rYHrJU3iYqI1e0MLlhCb"
}


2.5 商户验签规则

支付宝出口网关会对http请求加签,签名值放在sign参数中。签名参数包括两部分:业务参数(包括SPI接口定义的header、query、body参数)+系统参数(除去 sign、sign_type 以外的所有系统字段)。所有签名参数组装成待签名的map,然后对此map按照key的ASCII码从小到大排序并生成 k=v 字符串对,k=v对之间以"&"连接,然后待签名字符串按charset设定的编码类型、私钥及加签类型生成签名值。验签流程如下:


a)设置待验签参数

系统参数:

  • method=spi.xxx
  • charset=UTF-8
  • version=1.0
  • biz_app_id=2018XXX123
  • invoke_app_id=2018XXX321
  • utc_timestamp=1546077067


业务参数:

  • header_key=header_value
  • query_key=query_value
  • body_key=body_value


b)根据待验签参数key按ASCII顺序排序

  • biz_app_id=2018XXX123
  • body_key=body_value
  • charset=UTF-8
  • header_key=header_value
  • invoke_app_id=2018XXX321
  • method=spi.xxx
  • query_key=query_value
  • utc_timestamp=1546077067
  • version=1.0


c)生成待验签字符串

biz_app_id=2018XXX123&body_key=body_value&charset=UTF-8&header_key=header_value&invoke_app_id=2018XXX321&method=spi.xxx&query_key=query_value&utc_timestamp=1546077067&version=1.0


d)验签

使用非对称验签算法 RSA(SHA1withRSA)或者 RSA2(SHA256withRSA)对待验签字符串进行验签,具体验签算法由sign_type指定。


验签建议使用 支付宝开放平台SDK 封装的验签工具类进行验签,调用方法如下:

/**
 * 明文公钥模式:RSA/RSA2验签,sign和sign_type不参与验签
 * 
 * @param params    签名参数:业务参数(包括SPI接口定义的header、query、body参数)+系统参数(除去sign、sign_type以外的所有系统字段)
 * @param publicKey 支付宝公钥明文
 * @param charset   验签字符集
 * @param charset   验签算法(RSA/RSA2)
 */
boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, 
                                   String charset, String signType)
    
/**
 * 证书模式:RSA/RSA2验签,sign和sign_type不参与验签
 * 
 * @param params    签名参数:业务参数(包括SPI接口定义的header、query、body参数)+系统参数(除去sign、sign_type以外的所有系统字段)
 * @param alipayPublicCertPath 支付宝公钥证书
 * @param charset   验签字符集
 * @param charset   验签算法(RSA/RSA2)
 */
boolean AlipaySignature.rsaCertCheckV1(Map<String, String> params, String alipayPublicCertPath, 
                                       String charset, String signType)


2.6 商户签名规则

商户响应报文必须为 JSON 格式,含 sign 和 response 两个字段,如下:


{
    "response":{
        "code":"10000",
        "msg":"Success",
        "key":"value"
    },
    "sign":"xxx"
}



a)生成签名字符串

对 response 节点的值进行加签,待签名字符串为:


{
  "code":"10000",
  "msg":"Success",
  "key":"value"
}


b)签名

签名算法与签名算法一致,有sign_type指定。建议使用 支付宝开放平台SDK 封装的签名工具类进行签名,调用方法如下:

/**
 * RSA/RSA2签名,sign和sign_type不参与签名
 * 
 * @param content
 * @param privateKey
 * @param charset
 * @return
 * @throws AlipayApiException
 */
public static String rsaSign(String content, String privateKey, String charset, String signType)


3. 服务端实现 DEMO

以下 demo 是通过 Java 实现的 SPI 服务样例,包括验签 支付宝请求报文、业务逻辑处理、商户加签 以及 响应报文构造的逻辑。该demo仅供参考,不同语言环境可根据该demo的处理思路自行实现


    @RequestMapping(value = "/isv/spi/service")
    @ResponseBody 
    public String spiService(@RequestHeader HttpHeaders headers, 
                          @RequestParam Map<String, String> params) {
        // http响应结果载体
        JSONObject result = new JSONObject();
        // 业务处理结果载体
        JSONObject response = new JSONObject();         

        //header中的业务参数也参与签名(可选,根据SPI接口定义而定)
        params.put("header_biz1", headers.getFirst("header_biz1"));
        params.put("header_biz2", headers.getFirst("header_biz2"));

        // 1、验签支付宝请求报文
        boolean isPass = AlipaySignature.rsaCheckV1(params, alipayPublicKey, "UTF-8", "RSA2");

        if (isPass) {
            // 2、验签成功:处理业务逻辑,并构造业务处理结果
            response.put("code", "10000");
            response.put("msg", "Success");
            response.put("biz", "value");
            JSONObject person = new JSONObject();   
            person.put("age", "18");
            person.put("height", "180");
            response.put("person", person);  // response中嵌套复杂类型数据结构场景
        } else {
            // 验签失败:构造错误码
            response.put("code", "40004");
            response.put("msg", "Business Failed");
            response.put("sub_code", "ISV-VERIFICATION-FAILED");
            response.put("sub_msg", "验签失败");
        }

        // 3、业务处理结果加签
        // contentToSign 为 {"code":"10000","msg":"Success","biz":"value","person":{"age":"18","height":"180"}}
        String contentToSign = response.toJSONString(); 
        String sign = AlipaySignature.rsaSign(contentToSign, isvPrivateKey, "UTF-8", "RSA2");

        // 4、构造http响应结果
        result.put("sign", sign);
        result.put("response", response);

        // 返回json格式响应报文
        return result.toJSONString();
    }


onlineServer