联系人 逯浩圻(luhaoqi@hsifue.cn ) 李东岳(lidy-e@hsifue.cn)
如果您的服务不需要在isv订阅时做初始化的工具,那么可以跳过此步,但如果需要在isv订阅后为isv做一些初始化的工作,怎么办?
AECORE向SP提供了isv订阅事件的通知机制,当isv在AECORE订阅您的服务后,AECORE会向您在注册服务时所留的地址发送通知消息。


AECORE在向SP发送通知事件时,为安全起见,增加了签名机制,SP通过验签证明通知是由AECORE发出的,下面说明如何找到签名时采用的签名密钥
在技术服务中详情中查看密钥 
定义回调接口
{
"appCode":"appCode",
"appkey":"appkey",
"appName":"appName",
"contactEmail":"contactEmail",
"contactPhone":"contactPhone",
"resourceId":"resourceId",
"timestamp":"timestamp",
"signature":"signature",
"userId":"userId"
}
| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
| appCode | String | 是 | app编码 |
| appkey | String | 是 | 订阅的appkey |
| appName | String | 是 | 应用名称 |
| contactEmail | String | 是 | 联系邮箱 |
| contactPhone | String | 是 | 联系手机号 |
| resourceId | String | 是 | 技术服务的resourceId |
| timestamp | String | 是 | 订阅的时间 |
| userId | String | 是 | 订阅人 |
| signature | String | 是 | 签名 |
* 签名的生成方式为:
参数按照字母顺序排序,然后经过HMacSha256加密后,生成Base64编码。示例如下:
Base64(HmacSha256((appCode={appCode}&appKey={appKey}&appName={appName}&contactEmail={contactEmail}&contactPhone={contactPhone}&resourceId={resourceId}&signKey={signKey}×tamp={timestamp}&userId={userId})))
> signKey为第一步获取的密钥
{
"code": "success",
"message": null,
"data": "null"
}
| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
| code | String | 是 | 回调成功、失败(success、fail) |
样例程序
//验证签名示例
@PostMapping("/callback")
public ReSPonseBean<String> callback(@RequestBody CallBackBean callBackBean) {
String message = SHA256Utils.sha256_HMAC(MessageFormat.format("appCode={0}&appKey={1}&appName={2}&contactEmail={3}&contactPhone={4}&resourceId={5}&signKey={6}×tamp={7}&userId={8}", callBackBean.getAppCode(), callBackBean.getAppkey(), callBackBean.getAppName(),callBackBean.getContactEmail(), callBackBean.getContactPhone(), callBackBean.getResourceId(),
signKey, String.valueOf(callBackBean.getTimestamp()), callBackBean.getUserId()), signKey);
if (StringUtils.equals(callBackBean.getSignature(), message)) {
return ReSPonseBean.success();
} else {
return ReSPonseBean.fail("signature not true");
}
}
//CallBackBean定义
public class CallBackBean {
private String appCode;
private String appkey;
private String appName;
private String contactEmail;
private String contactPhone;
private String resourceId;
private Long timestamp;
private String userId;
private String signature;
public CallBackBean() {
}
}
//签名工具类
import javax.crypto.Mac;
import javax.crypto.SPec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
public class SHA256Utils {
public static String sha256_HMAC(String message, String secret) throws NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeyException {
Mac hmacSha256 = Mac.getInstance("HmacSHA256");
byte[] keyBytes = secret.getBytes("UTF-8");
hmacSha256.init(new SecretKeySpec(keyBytes, 0, keyBytes.length, "HmacSHA256"));
String sign = Base64.getEncoder().encodeToString(hmacSha256.doFinal(message.getBytes("UTF-8")));
return sign;
}
}
当ISV来调用时,我如何知道是哪个ISV调用了我的服务?
因为ISV是带着OAuth2 token通过AECORE网关apigate.hsifue.cn来调用SP服务的,所以,AECORE能够从token中识别出来ISV的身份,将识别出来的身份信息放入到http header "x-token-info"中发向SP服务。

x-token-info以json格式存储ISV身份信息,如果是应用token,对应的字段说明如下
{
"scope": [],
"exp": 1594637537,
"resource_ids": [],
"client_authorities": [
{
"authority": "ROLE_RESOURCE"
},
{
"authority": "ROLE_CLIENT"
}
],
"client_name": "test-app", //isv应用名称
"client_id": "YBOiBzRKS2jqkXbYEAhrWYV9qDw0kWw1", //isv的appKey
"oauth_client_id": "isv-Bhavhi78KT"
}
如果是用户token,对应字段说明如下
{
"user_id": 5889529351866831698,//用户在用户中心的userId
"scope": [],
"global_id": "2757867",//用户在用户中心的globalId
"exp": 1595385280,
"resource_ids": [],
"user_authorities": [
{
"authority": "ROLE_USER"
}
],
"client_authorities": [
{
"authority": "ROLE_RESOURCE"
},
{
"authority": "ROLE_CLIENT"
}
],
"client_name": "demo-app-02", //isv应用名称
"client_id": "CTvOVmGy1JdgLlFx5xXiPc4la0OfPWw4",//isv的appKey
"oauth_client_id": "isv-7KEleRxGRw"
}
判断用户是够具有相应的操作权限。
同时,为保障x-token-info的安全性,AECORE对其进行了签名,放在http header "x-token-info-sign"中,签名内容即为x-token-info,算法见上面的SHA256Utils。