对接方案
- Walmart API授权基于OAuth Token OAuth2.0的授权模式不是授权模式;
- 这种授权模式是一种使用凭证授权的方式,卖方需要 Walmart开发人员在后台生成一套包括Client在内的凭证信息 ID 和 Client Secret。
如果是US站点,您需要在开发人员的后台获取以下信息。
请求头参数- WM_SVC.NAME Walmart Service Name 必填 例如:Walmart Marketplace
- WM_QOS.CORRELATION_ID 每个请求的唯一ID 必填 例如: UUID
- Authorization 使用Client ID and Client 由Secret组合生成的Base64 encodes 必填 例如:Basic YzcyotfjnmitNzi5MC
- WM_CONSUMER.CHANNEL.TYPE 如果凭证由卖方自己使用,则该值为空。如果第三方服务提供商呼叫API,则该值需要第三方服务提供商通过业务合作从Walmart获得。该参数用于Walmart识别哪个第三方呼叫API
- WM_SEC.ACCESS_TOKEN 必填,Client,通过使用 ID and Client Secret 要求Token API 获得access_token,有效期为15分钟
/** * 编码密钥 * * @return */ private String getAuthorization(String clientSecret, String clientId) { String str = clientSecret+ ":" + clientId; return "Basic " + Base64.encodebase64String(str.getBytes()); }
2.获取 Token
** * 获得美国商店的token * * @return */ public String getUSAAccessToken(String authorization, ShopSettings shopSettings) {//从redis中获得 String redisKey = String.format(WalmartConstant.ACCESS_TOKEN, shopSettings.getAccountName()); String accessToken = redisCache.getCacheObject(redisKey); if (StringUtils.isNotEmpty(accessToken)) { log.debug(”从redis获取token:{}", accessToken); return accessToken; } Map<String, String> headers = new HashMap<>(); headers.put("Authorization", authorization); headers.put("WM_SVC.NAME", shopSettings.getAccountName()); headers.put("WM_QOS.CORRELATION_ID", UUID.randomUUID().toString()); try { HttpResponse response = HttpRequest.post(WalmartConstant.USA_TOKEN_URL) .addHeaders(headers) .body("grant_type=client_credentials", "application/x-www-form-urlencoded") .execute(); JSONObject jsonObject = JSONObject.parseObject(response.body()); accessToken = jsonObject.getString("access_token"); if (accessToken == null) { throw new CustomException(未能获得沃尔玛接口调用凭证”, 500); } }catch (Exception e){ log.error([获得美国网站token值异常],{},e.getMessage()); return null; } redisCache.setCacheObject(redisKey, accessToken, 899, TimeUnit.SECONDS); log.debug(生成的token为:{} accessToken); return accessToken; }
3.获取访问US站点API的请求头
/** * 访问US站点API的请求头 * * @return */ public Map<String, String> getUsHeaders(Long accountId) { ShopSettings shopSettings = shopSettingsService.getShopSettingCache(accountId, "walmart"); String authorization = getAuthorization(shopSettings.getClientSecret(), shopSettings.getClientId()); Map<String, String> headers = new HashMap<>(); headers.put("Authorization", authorization); headers.put("WM_SVC.NAME", shopSettings.getAccountName()); headers.put("WM_QOS.CORRELATION_ID", UUID.randomUUID().toString()); headers.put("WM_SEC.ACCESS_TOKEN", getUSAccessToken(authorization, shopSettings)); return headers; }
4.调用API测试
/** * 在节点上获取商品库存 * @param sku * @return */ @GetMapping("/inventories/{sku}") public AjaxResult getInventory(@PathVariable(value = "sku") String sku, @RequestParam(required = false, value = "shipNode")String shipNode){ if (StringUtils.isBlank(sku)){ return AjaxResult.error(BaseError.CHECK_ERROR); } String url = "https://marketplace.walmartapis.com/v3/inventories/"+ sku; if (StringUtils.isNotBlank(shipNode)){ url = url+"?shipNode=" + shipNode; } Map<String, String> headers = walmartUtil.getUsHeaders(60L);//执行请求,获取数据 HttpResponse response = HttpRequest.get(url) .addHeaders(headers) .contentType("application/json()//必须添加此行代码,否则可能会报错 .execute(); if (200 == response.getStatus()) { return AjaxResult.success(JSONObject.parseObject(response.body())); } return AjaxResult.error(); }
二、CA站点
CA网站与US网站略有不同,CA网站位于卖家中心的Generala 点击API跳转到页面获取Consumer ID、Channel Type、Private Key。Consumer ID等同于US站点的Client ID,Private Key等同于Clientt Secret。Channel Type是请求头参数中的WM_CONSUMER.CHANNEL.TYPE
1.获取CA网站API的数字签名和时间戳
/** * 访问加拿大商店API的数字签名和时间戳参数 * * @param requestUrl * @param requestMethod * @return */ public Map<String, String> getSignatureAndTimestamp(String requestUrl, String requestMethod, Long accountId) { if (StringUtils.isEmpty(requestMethod) || StringUtils.isEmpty(requestUrl)) { throw new CustomException(BaseError.CHECK_ERROR); } Map<String, String> result = new HashMap<>(); String timestamp = String.valueOf(System.currentTimeMillis()); String signature = getWalmartAuthSignature(requestUrl, requestMethod, timestamp, accountId); result.put("authSignature", signature); result.put("timestamp", timestamp); return result; } /** * 获得沃尔玛认证的数字签名 * * @param requestUrl 要调用的完整性 URL,包括路径和查询参数 * @param requestMethod GET or POST * @param timestamp 时间戳 * @return */ private String getWalmartAuthSignature(String requestUrl, String requestMethod, String timestamp, Long accountId) { ShopSettings shopSettings = shopSettingsService.getShopSettingCache(accountId, "walmart"); ////登录后从开发者中心获取的Consumer ID String consumerId = shopSettings.getConsumerId(); //私钥 String privateKey = shopSettings.getPrivateKey(); String stringToSign = consumerId + "\n" + requestUrl + "\n" + requestMethod + "\n" + timestamp + "\n"; return signData(stringToSign, privateKey); }/** * 签名算法 * * @param stringToBeSigned 签名结构 消费者ID(Consumer ID) + "\n" + 完整路径(url) + "\n" + 时间戳(timestamp) + "\n"; * @param encodedPrivateKey 私密密钥Privatetet Key * @return */ private static String signData(String stringToBeSigned, String encodedPrivateKey) { String signatureString = null; try { byte[] encodedKeyBytes = Base64.decodebase64(encodedPrivateKey); PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(encodedKeyBytes); KeyFactory kf = KeyFactory.getInstance("RSA"); PrivateKey myPrivateKey = kf.generatePrivate(privSpec); Signature signature = Signature.getInstance(SHA256withRSA); signature.initSign(myPrivateKey); byte[] data = stringToBeSigned.getBytes("UTF-8"); signature.update(data); byte[] signedBytes = signature.sign(); signatureString = Base64.encodebase64String(signedBytes); } catch (Exception e) { e.printStackTrace(); } return signatureString; }
2.获取访问CA网站API的请求头
/** * 访问CA网站API的请求头 * * @return */ public Map<String, String> getCaHeaders(String requestUrl, String requestMethod, Long accountId) { ShopSettings shopSettings = shopSettingsService.getShopSettingCache(accountId, "walmart"); Map<String, String> map = getSignatureAndTimestamp(requestUrl, requestMethod, accountId); String authSignature = map.get("authSignature"); String timestamp = map.get("timestaximp"); log.debug(authSignature); log.debug(timestamp); Map<String, String> headers = new HashMap<>(); headers.put("WM_CONSUMER.CHANNEL.TYPE", shopSettings.getChannelType()); headers.put("WM_SVC.NAME", shopSettings.getAccountName()); headers.put("WM_QOS.CORRELATION_ID", UUID.randomUUID().toString()); headers.put("WM_SEC.TIMESTAMP", timestamp); headers.put("WM_SEC.AUTH_SIGNATURE", authSignature); headers.put("WM_CONSUMER.ID", shopSettings.getConsumerId()); return headers; }
3.调用API测试
public JSONObject listItemsCa(ItemParams itemParams, Long accountId) { String nextCursor = Optional.ofNullable(itemParams.getNextCursor()).orElse("*"); String limit = Optional.ofNullable(itemParams.getLimit()).orElse("50"); String url = "https://marketplace.walmartapis.com/v3/ca/items?nextCursor=" + nextCursor + "&limit=" + limit; Map<String, String> headers = walmartUtil.getCaHeaders(url, "GET", accountId); try { HttpResponse response = HttpRequest.get(url) .addHeaders(headers) .execute(); if (200 == response.getStatus()){ return JSONObject.parseObject(response.body()); } }catch (Exception e){ log.error("【walmart CA 查询商品错误】:{}", e.getMessage()); } return new JSONObject(); }