1.1.支付宝定义两种类型接口:
1.2 接口列表:
| 英文名称 | 中文名称 | 使用场景 | 文档 |
| spi.alipay.commerce.educate.certification.campuscard.query |
认证学生信息查询 |
支付宝调用认证机构接口验证学生身份 |
|
| alipay.commerce.educate.authenticate.campuscard.create | 高校ISV认证信息同步 | 合作ISV同步认证的学生信息到支付宝。 | 查看 |
采用https的方式向服务商发送数据请求。
SPI 的接入流程如下图所示:

支付宝:
第三方系统服务商:
根据支付宝 SPI 的相关规范完成 SPI 的开发。支付宝调用第三方系统服务商SPI服务前需要完成 SPI 功能包的添加并成功发布服务,
| 步骤 |
事项 |
入口 |
| 第一步 |
第三方服务商创建一个应用(创建应用),第三方应用授权、小程序,网页应用都可以 |
|
| 第二步 |
配置应用。登录开放平台,配置应用环境,包括添加应用功能,上传RSA2的公钥、授权回调地址等。 |
获取创建应用并获取 APPID,详见配置密钥 |
| 第三步 |
添加 SPI 功能包。 实现 SPI 服务时,第三方系统服务商(ISV)需先关联相关产品,关联产品的入口有两个:a.从应用详情页挂载功能包的列表页;b.从能力中心的列表页获取 |
参考添加SPI功能包 |
| 第四步 |
1.接口管理:查看场景的基本信息以及详细文档 2.接口接入:使用开放平台上提供的测试工具在线测试。 3.在线测试:填入对应的参数。(业务入参【主要包括三部分:header参数、query参数、body参数、】) 4.接口审核:SPI 接口联调通过以后可以发起接口审核. 5.能力发布上线审核 |
参考文档第四步 |
| 第五步 |
服务端接口开发 1.下载服务端SDK 2.支付宝SPI通信规范说明 3.请求、响应报文格式说明 4.加验签格式说明 5.参考DEMO获取 |
参考文档第五步 |
1.接口名称
spi.alipay.commerce.educate.certification.campuscard.query(认证学生信息查询)
2.2.通信规范
2.2.1 协议规则
外部商户接入支付宝开放平台出口网关,提供的服务必须满足以下规范:
| 网络传输协议 |
支持 http、https |
| 数据提交方法 |
支持 GET、POST |
| Content-Type |
application/x-www-form-urlencoded |
| 响应报文格式 |
JSON |
| 签名算法 |
支持 RSA、RSA2 |
| 字符集 |
支持 GBK、UTF-8 |
2.2.2 请求报文格式
Header 参数
由 SPI 接口文档中的 Header 参数定义,Header中的key具有固定前缀"x_"。
Query 参数(支付宝开放平台接口统一规范,仅供参考,测试工具中已固定传入,无需在工具中填写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 |
是 |
签名值 |
*** |
|
| 业务字段(自定义) |
无 |
||||
Body 参数
由 SPI 接口文档中的 Body 参数定义,Content-Type为:application/x-www-form-urlencoded。
| 名称 | 具体类型 | 是否必填 | 最大长度 | 示例值 | 描述 |
|---|---|---|---|---|---|
| school_stdcode | String | 必选 | 32 |
4136013438
|
学校国标码
|
| name | String | 必选 | 10 |
王小二
|
姓名
|
| cert_type | String | 可选 | 10 |
1(身份证),A(护照)
|
证件类型
|
| cert_no | String | 可选 | 64 |
21010319940617344X
|
证件号
|
| card_number | String | 可选 | 64 |
1334900
|
学号
|
| password | String | 可选 | 64 |
123456
|
一卡通密码
|
2.2.3 响应报文格式
响应参数定义
| 字段 |
类型 |
是否必填 |
描述 |
示例值 |
| response |
String |
是 |
JSON格式字符串 |
{"code":"10000","msg":"success","key_1":"Value1"} |
| sign |
String |
是 |
签名值 |
TqnBnkILs86FJWRqWWZptqIpSKLIp2vnwod177h7GLyWuLhzgRHpXgXd8GoD 4flyHrHBTycQdiUjWw6VqCE5rYHrJU3iYqI1e0MLlhCb |
| 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 接口文档中的响应参数见下表 |
|||
业务字段:
| 名称 | 具体类型 | 是否必填 | 是否脱敏 | 最大长度 | 示例值 | 描述 |
|---|---|---|---|---|---|---|
| name | String | 必选 | 否 | 10 |
王小二
|
姓名
|
| school_stdcode | String | 必选 | 否 | 32 |
4136013438
|
学校国标码
|
| school_name | String | 可选 | 否 | 10 |
同济大学
|
学校名称
|
| status | String | 可选 | 否 | 10 |
0(在校)
|
在校状态
|
| short_code | String | 必选 | 否 | 32 |
1234567890
|
自然人在学校范围内唯一码标识,用于生成校园码
|
| expire_at | Date | 必选 | 否 | 10 |
2019-10-01
|
预期毕业(离校)时间,精确到日
|
| campus_no | String | 可选 | 否 | 32 |
1234567890
|
学号或教工号
|
| ext_info | String | 可选 | 否 | 1024 |
{"email":"092806@tongji.edu.cn"}
|
扩展字段
|
| 统一对外错误码 | 错误描述 | 解决方案 |
|---|---|---|
| SYSTEM_ERROR |
系统繁忙
|
通用异常,需要联系ISV
|
| SCHOOL_NOT_MAPPING |
学校不匹配
|
学校不匹配
|
| STUDENT_NOT_EXIST |
学生不存在
|
学生不存在
|
| STUDENT_EXPIRED |
学籍已过期
|
学籍已过期
|
{
"response":{
"code":"10000",
"msg":"Success",
"name":"王小二",
"school_stdcode":"4136013438",
"school_name":"同济大学",
"status":"0(在校)",
"short_code":"1234567890",
"expire_at":"2019-10-01",
"campus_no":"1234567890",
"ext_info":"{\"email\":\"092806@tongji.edu.cn\"}"
}
,"sign":"ERITJKEIJKJHKKKKKKKHJEREEEEEEEEEEE"
}
{
"response":{
"code":"40004",
"msg":"Business Failed",
"sub_code":"INVALID_PARAMS",
"sub_msg":"无效参数"
},
"sign":"TqnBnkILs86FJWRqWWZptqIpSKLIp2vnwod177h7GLyWuLhzgRHpXgXd8GoD4flyHrHBTycQdiUjWw6VqCE5rYHrJU3iYqI1e0MLlhCb"
}
说明:目前支付宝开放平台有两种加密方式,一种是RSA2公私钥方式,一种是证书方式。上例为
RSA2公私钥方式。证书方式可参考
SPI 三方服务接入指南
2.2.5商户验签规则
支付宝出口网关会对http请求加签,签名值放在sign参数中。签名参数包括两部分:业务参数(包括SPI接口定义的header、query、body参数)+系统参数(除去 sign、sign_type 以外的所有系统字段)。所有签名参数组装成待签名的map,然后对此map按照key的ASCII码从小到大排序并生成 k=v 字符串对,k=v对之间以"&"连接,然后待签名字符串按charset设定的编码类型、私钥及加签类型生成签名值。验签流程如下:
a)设置待验签参数
系统参数:
业务参数:
b)根据待验签参数key按ASCII顺序排序
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.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)
2.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();
}
合作ISV同步认证的学生信息到支付宝,需要调用openapi同步认证数据,默认用户是已认证的状态。
3.1.接口名称:
alipay.commerce.educate.authenticate.campuscard.create(高校ISV认证信息同步)
3.2.入参:
| 名称 | 具体类型 | 是否必填 | 最大长度 | 示例值 | 描述 |
|---|---|---|---|---|---|
| cert_no | String | 必选 | 32 |
21020119980615433X
|
证件号
|
| cert_type | String | 必选 | 10 |
学生证件类型,默认为1: 1 居民身份证
|
证件类型
|
| user_name | String | 必选 | 10 |
王小二
|
用户姓名
|
| campus_no | String | 必选 | 32 |
1234567890
|
自然人在学校唯一编号
|
| gender | String | 可选 | 10 |
学生性别,0未知,1男,2女,9未说明的性别
|
性别
|
| school_stdcode | String | 必选 | 32 |
1234567890
|
学校国标码
|
| school_name | String | 必选 | 32 |
同济大学
|
学校名称
|
| campus | String | 可选 | 32 |
嘉定校区
|
校区
|
| organization | String | 可选 | 128 |
年级/学院/班级
|
组织信息,多个分组以;隔开:AA/BB/CC;A/B/C
|
| expire_at | Date | 必选 | 10 |
2019-01-01
|
毕业时间
|
| isv_short_code | String | 必选 | 32 |
123456789
|
学生/教职工在学校唯一短号,由isv分配
|
| ext_info | String | 可选 | 1024 |
{"name":"123"}
|
扩展字段,json格式
|
| card_type | String | 可选 | 10 |
1
|
1学生卡,2教工卡,3临时卡,4其他 不传默认是学生卡
|
| 名称 | 具体类型 | 是否必填 | 是否脱敏 | 最大长度 | 示例值 | 描述 |
|---|---|---|---|---|---|---|
| result | String | 必选 | 否 | 10 |
SUCCESS
|
如果学生学籍插入成功,则返回SUCCESS , 失败返回FAIL
|
| 统一对外错误码 | 内部业务错误码 | 错误描述 | 解决方案 |
|---|---|---|---|
| SYSTEM_EXCEPTION | SYSTEM_EXCEPTION |
系统繁忙
|
联系支付宝小二处理
|
| INVALID_PARAMETER | INVALID_PARAMETER |
参数有误
|
请详细阅读接口文档
|
| SCHOOL_NOT_EXIST | SCHOOL_NOT_EXIST |
学校信息不存在
|
请联系支付宝小二入驻学校
|
| CONTRACT_ERROR | CONTRACT_ERROR |
学校未签约服务
|
请联系支付宝小二完成学校签约
|
3.3以java为例调用代码
AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do","app_id","your private_key","json","GBK","alipay_public_key","RSA2");
AlipayCommerceEducateAuthenticateCampuscardCreateRequest request = new AlipayCommerceEducateAuthenticateCampuscardCreateRequest();
request.setBizContent("{" +
"\"cert_no\":\"21020119980615433X\"," +
"\"cert_type\":\"学生证件类型,默认为1: 1 居民身份证\"," +
"\"user_name\":\"王小二\"," +
"\"campus_no\":\"1234567890\"," +
"\"gender\":\"学生性别,0未知,1男,2女,9未说明的性别\"," +
"\"school_stdcode\":\"1234567890\"," +
"\"school_name\":\"同济大学\"," +
"\"campus\":\"嘉定校区\"," +
"\"organization\":\"年级/学院/班级\"," +
"\"expire_at\":\"2019-01-01\"," +
"\"isv_short_code\":\"123456789\"," +
"\"ext_info\":\"{\\\"name\\\":\\\"123\\\"}\"," +
"\"card_type\":\"1\"" +
" }");
AlipayCommerceEducateAuthenticateCampuscardCreateResponse response = alipayClient.execute(request);
if(response.isSuccess()){
System.out.println("调用成功");
} else {
System.out.println("调用失败");
}
响应示例:
{
"alipay_commerce_educate_authenticate_campuscard_create_response":{
"code":"10000",
"msg":"Success",
"result":"SUCCESS"
}
,"sign":"ERITJKEIJKJHKKKKKKKHJEREEEEEEEEEEE"
}