一、前言
目的:将抖音团购核销的功能集成到我们自己开发的App和小程序中
二、授权流程
- 以杆知乐(24小时自助台球棋牌)为例。
三、授权Url
- 业务授权URL:https://auth.dylk.com/auth-isv/
https://auth.dylk.com/auth-isv/?client_key=awxxxxxxxx×tamp=1677686399&sign=xxxxxxxxxxxxxx&solution_key=1&permission_keys=1,16&out_shop_id=shop_id&charset=UTF-8&extra=aaaaaaaaaa
3.1 Url参数表
字段 | 含义 | 必填 |
---|---|---|
client_key | 服务商应用标示 | 是 |
timestamp | url开始生效的秒时间戳 ,24小时内有效 | 是 |
solution_key | 到店餐饮1,到店团购2,随心团5 | 是 |
permission_keys | 授权能力如2.2表 | 是 |
charset | 交互数据的编码 固定值:UTF-8 | 是 |
sign | 根据参数内容生成的签名 | 是 |
client_key | 服务商应用标示 | 是 |
out_shop_id | 绑定抖音门店的外部门店ID | 否 |
3.2 授权能力表
能力枚举permission_keys | 语义 |
---|---|
1 | 门店管理 |
2 | 订单查询 |
3 | 门店基础信息更新 |
4 | 门店任务查询 |
5 | 同步门店户 |
6 | 门店匹配 |
7 | 门店装修 |
8 | 门店亮照 |
9 | 会员管理 |
10 | 商品查询 |
11 | 商品发布 |
12 | 团购核销 |
13 | cps佣金设置与查询 |
14 | KA核销对账 |
15 | 团购核销对账 |
16 | 商户授权 |
17 | 三方码发布 |
18 | 同步品牌户 |
19 | 客资查询 |
3.3 源码示例
- 快速生成商家授权链接
private final static String AuthUrl = "https://auth.dylk.com/auth-isv/";
public static String genAuthWithBindValidUrlFast(String outShopId) {
Map<String, String> query = new HashMap<>();
query.put("client_key", APPID);
query.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
query.put("charset", "UTF-8");
query.put("solution_key", "4");
query.put("out_shop_id", outShopId);
query.put("permission_keys", "1,2,10,12,14,15,16");
String signResult = SignUtil.signV2(AppSecret, "", query);
query.put("sign", signResult);
String queryStr = query.entrySet().stream()
.map(entry -> new StringBuilder().append(entry.getKey()).append("=").append(entry.getValue()))
.collect(Collectors.joining("&"));
StringBuilder resultSb = new StringBuilder(AuthUrl).append("?").append(queryStr);
return resultSb.toString();
}
- 签名加密
SignUtil.java
/**
* SignV2 用于生活服务应用计算header中的签名(sha256) 新申请应用请使用该方法计算
* @param clientSecret 应用secret
* @param body post请求/spi请求中的body参数json字符串
* @param query url参数
* @return 签名
*/
public static String signV2(String clientSecret, String body, Map<String, String> query) {
StringBuilder str = new StringBuilder(clientSecret);
query.keySet().stream()
.filter(a -> !"sign".equals(a))
.sorted()
.forEach(k -> {
String val = query.get(k);
str.append("&");
str.append(k).append("=").append(val);
});
if (body != null && !"".equals(body)) {
str.append("&");
str.append("body").append("=").append(body);
}
System.out.printf("[Sign] v2 str:%s\n", str.toString());
String result = SHA256(str.toString());
System.out.printf("[Sign] v2 str:%s, result:%s\n", str.toString(), result);
return result;
}
/**
* SHA-256加密
* @param input 明文
* @return 密文
*/
public static String SHA256(String input) {
String result = "";
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(input.getBytes(StandardCharsets.UTF_8));
byte[] digest = md.digest();
result = bytes2Hex(digest);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return result;
}
四、授权回调
4.1 添加授权回调接口
抖音开放平台(服务商平台)
第三方生活服务商家应用
开发设置
Webhooks
- 添加你写好的接口,如果你的接口没写好,则会提示
参数不合法
- 如果接口是ok的,则会提示添加成功。
4.2 授权回调接口源码示例
- 校验签名,加密请求体与请求体的签名进行对比
- 判断是key和event无误
- 则保存商户授权信息
/**
* 抖音推送接口
*/
@PostMapping("/douyin/messages")
public String douyinMessage(@RequestBody String body, @RequestHeader Map<String, String> headers)
{
log.info(body);
log.info(headers.toString());
// 获取请求头中的加签信息
String douyinSign = headers.get("X-Douyin-Signature");
if(douyinSign==null || douyinSign.length()==0){
douyinSign = headers.get("x-douyin-signature");
}
String data = DouYinUtils.AppSecret + body;
String sign = DigestUtils.sha1Hex(data);
if(!sign.equals(douyinSign)){
log.error("验签失败, data="+data);
log.error("验签失败, sign1="+sign);
log.error("验签失败, sign2="+douyinSign);
return AjaxResult.error().toString();
}
JSONObject douyinData = JSONObject.parseObject(body);
if(douyinData.getString("client_key").equals(DouYinUtils.APPID)){
if(douyinData.getString("event").equals("life_saas_cooperate_auth_with_bind")){
String content = douyinData.getString("content");
JSONObject jsonObject = JSONObject.parseObject(content);
Long shopId = Long.valueOf(jsonObject.getString("out_shop_id"));
String accountId = jsonObject.getString("account_id");
String solutionKey = jsonObject.getString("solution_key");
String permissionKey = jsonObject.getJSONArray("permission_keys").toJSONString();
BilliardsDouyin billiardsDouyin = new BilliardsDouyin();
billiardsDouyin.setAccountId(accountId);
billiardsDouyin.setPermissionKeys(permissionKey);
billiardsDouyin.setSolutionKey(solutionKey);
billiardsDouyin.setShopId(shopId);
log.info(billiardsDouyin.toString());
billiardsDouyinService.insertBilliardsDouyin(billiardsDouyin);
BilliardsShop billiardsShop = billiardsShopService.selectBilliardsShopById(shopId);
if (ObjectUtil.isNull(billiardsShop)) {
log.error("抖音商家授权回调接口,查无此球厅");
return AjaxResult.error().toString();
}
billiardsShop.setDouyinId(accountId);
billiardsShopService.updateBilliardsShop(billiardsShop);
}
}
return douyinData.getJSONObject("content").toJSONString();
}
五、实际操作演示
六、参考
觉得好,就一键三连呗(点赞+收藏+关注)