Compare commits

...

11 Commits

  1. 2
      sop-admin/sop-admin-server/src/main/resources/META-INF/sop-admin.properties
  2. 3
      sop-common/sop-bridge-gateway/src/main/java/com/gitee/sop/bridge/SopGatewayAutoConfiguration.java
  3. 3
      sop-common/sop-bridge-zuul/src/main/java/com/gitee/sop/bridge/SopGatewayAutoConfiguration.java
  4. 10
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/taobao/Constants.java
  5. 97
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/taobao/TaobaoSignature.java
  6. 50
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/taobao/TaobaoSigner.java
  7. 3
      sop-example/sop-story/src/main/java/com/gitee/sop/storyweb/config/OpenServiceConfig.java
  8. 45
      sop-example/sop-story/src/main/java/com/gitee/sop/storyweb/controller/TaobaoController.java

@ -7,7 +7,7 @@ spring.application.name=sop-admin
# session过期时间,分钟 # session过期时间,分钟
admin.access-token.timeout-minutes=30 admin.access-token.timeout-minutes=30
# 签名方式,rsa:支付宝开放平台签名方式,md5:淘宝开放平台签名方式 # 签名方式,rsa:支付宝开放平台签名方式,md5:淘宝开放平台签名方式
sop.sign-type=rsa sop.sign-type=md5
# nacos配置 # nacos配置
nacos.config.server-addr=${nacos.url} nacos.config.server-addr=${nacos.url}

@ -2,6 +2,7 @@ package com.gitee.sop.bridge;
import com.gitee.sop.gatewaycommon.config.BaseGatewayAutoConfiguration; import com.gitee.sop.gatewaycommon.config.BaseGatewayAutoConfiguration;
import com.gitee.sop.gatewaycommon.gateway.configuration.AlipayGatewayConfiguration; import com.gitee.sop.gatewaycommon.gateway.configuration.AlipayGatewayConfiguration;
import com.gitee.sop.gatewaycommon.gateway.configuration.TaobaoGatewayConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration; import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@ -12,7 +13,7 @@ import org.springframework.context.annotation.Import;
* @author tanghc * @author tanghc
*/ */
@Configuration @Configuration
@Import(AlipayGatewayConfiguration.class) @Import(TaobaoGatewayConfiguration.class)
@AutoConfigureBefore(RibbonAutoConfiguration.class) @AutoConfigureBefore(RibbonAutoConfiguration.class)
public class SopGatewayAutoConfiguration extends BaseGatewayAutoConfiguration { public class SopGatewayAutoConfiguration extends BaseGatewayAutoConfiguration {
} }

@ -2,6 +2,7 @@ package com.gitee.sop.bridge;
import com.gitee.sop.gatewaycommon.config.BaseGatewayAutoConfiguration; import com.gitee.sop.gatewaycommon.config.BaseGatewayAutoConfiguration;
import com.gitee.sop.gatewaycommon.zuul.configuration.AlipayZuulConfiguration; import com.gitee.sop.gatewaycommon.zuul.configuration.AlipayZuulConfiguration;
import com.gitee.sop.gatewaycommon.zuul.configuration.TaobaoZuulConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration; import org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy; import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@ -14,7 +15,7 @@ import org.springframework.context.annotation.Import;
*/ */
@Configuration @Configuration
@EnableZuulProxy @EnableZuulProxy
@Import(AlipayZuulConfiguration.class) @Import(TaobaoZuulConfiguration.class)
// 在ErrorMvcAutoConfiguration之前加载 // 在ErrorMvcAutoConfiguration之前加载
// 如果不加会出现basicErrorController和zuulErrorController冲突 // 如果不加会出现basicErrorController和zuulErrorController冲突
// zuulErrorController是SOP中的,提前加载后basicErrorController就不会加载 // zuulErrorController是SOP中的,提前加载后basicErrorController就不会加载

@ -0,0 +1,10 @@
package com.gitee.sop.gatewaycommon.validate.taobao;
/**
* @author tanghc
*/
public class Constants {
public static final String SIGN_METHOD_HMAC = "hmac";
public static final String SIGN_METHOD_MD5 = "md5";
public static final String CHARSET_UTF8 = "UTF-8";
}

@ -0,0 +1,97 @@
package com.gitee.sop.gatewaycommon.validate.taobao;
import com.gitee.sop.gatewaycommon.validate.alipay.StringUtils;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Map;
/**
* @author tanghc
*/
public class TaobaoSignature {
public static String signTopRequest(Map<String, String> params, String secret, String signMethod) throws IOException {
String content = getSignContent(params);
return doSign(content, secret, signMethod);
}
public static String getSignContent(Map<String, ?> params) {
// 第一步:检查参数是否已经排序
String[] keys = params.keySet().toArray(new String[0]);
Arrays.sort(keys);
// 第二步:把所有参数名和参数值串在一起
StringBuilder query = new StringBuilder();
for (String key : keys) {
Object val = params.get(key);
String value = val == null ? null : val.toString();
if (StringUtils.areNotEmpty(key, value)) {
query.append(key).append(value);
}
}
return query.toString();
}
public static String doSign(String content,String secret, String signMethod) throws IOException {
// 第三步:使用MD5/HMAC加密
byte[] bytes;
if (Constants.SIGN_METHOD_HMAC.equals(signMethod)) {
bytes = encryptHMAC(content, secret);
} else {
bytes = encryptMD5(secret + content + secret);
}
// 第四步:把二进制转化为大写的十六进制(正确签名应该为32大写字符串,此方法需要时使用)
return byte2hex(bytes);
}
public static byte[] encryptHMAC(String data, String secret) throws IOException {
byte[] bytes = null;
try {
SecretKey secretKey = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacMD5");
Mac mac = Mac.getInstance(secretKey.getAlgorithm());
mac.init(secretKey);
bytes = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
} catch (GeneralSecurityException gse) {
throw new IOException(gse.toString());
}
return bytes;
}
public static byte[] encryptMD5(String data) throws IOException {
return encryptMD5(data.getBytes(StandardCharsets.UTF_8));
}
public static byte[] encryptMD5(byte[] data) {
try {
MessageDigest digest = MessageDigest.getInstance(Constants.SIGN_METHOD_MD5);
return digest.digest(data);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
public static String byte2hex(byte[] bytes) {
StringBuilder sign = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
String hex = Integer.toHexString(bytes[i] & 0xFF);
if (hex.length() == 1) {
sign.append("0");
}
sign.append(hex.toUpperCase());
}
return sign.toString();
}
}

@ -5,62 +5,30 @@ import com.gitee.sop.gatewaycommon.bean.SopConstants;
import com.gitee.sop.gatewaycommon.message.ErrorEnum; import com.gitee.sop.gatewaycommon.message.ErrorEnum;
import com.gitee.sop.gatewaycommon.param.ApiParam; import com.gitee.sop.gatewaycommon.param.ApiParam;
import com.gitee.sop.gatewaycommon.validate.AbstractSigner; import com.gitee.sop.gatewaycommon.validate.AbstractSigner;
import com.gitee.sop.gatewaycommon.validate.SignConfig; import lombok.extern.slf4j.Slf4j;
import com.gitee.sop.gatewaycommon.validate.SignEncipher;
import com.gitee.sop.gatewaycommon.validate.SignEncipherHMAC_MD5;
import com.gitee.sop.gatewaycommon.validate.SignEncipherMD5;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList; import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/** /**
* 淘宝开放平台签名验证实现http://open.taobao.com/doc.htm?docId=101617&docType=1 * 淘宝开放平台签名验证实现http://open.taobao.com/doc.htm?docId=101617&docType=1
* *
* @author tanghc * @author tanghc
*/ */
@Slf4j
public class TaobaoSigner extends AbstractSigner { public class TaobaoSigner extends AbstractSigner {
private Map<String, SignEncipher> signEncipherMap = new HashMap<>();
public TaobaoSigner() {
signEncipherMap.put("md5", new SignEncipherMD5());
signEncipherMap.put("hmac", new SignEncipherHMAC_MD5());
}
@Override @Override
public String buildServerSign(ApiParam param, String secret) { public String buildServerSign(ApiParam param, String secret) {
String signMethod = param.fetchSignMethod(); String signMethod = param.fetchSignMethod();
if (signMethod == null) { if (signMethod == null) {
signMethod = SopConstants.DEFAULT_SIGN_METHOD; signMethod = SopConstants.DEFAULT_SIGN_METHOD;
} }
SignEncipher signEncipher = signEncipherMap.get(signMethod); String signContent = TaobaoSignature.getSignContent(param);
if (signEncipher == null) { try {
throw ErrorEnum.ISV_INVALID_SIGNATURE_TYPE.getErrorMeta().getException(signMethod); return TaobaoSignature.doSign(signContent, secret, signMethod);
} catch (IOException e) {
log.error("淘宝签名失败, param:{}", param, e);
throw ErrorEnum.ISP_UNKNOWN_ERROR.getErrorMeta().getException();
} }
// 第一步:参数排序
Set<String> keySet = param.keySet();
List<String> paramNames = new ArrayList<>(keySet);
Collections.sort(paramNames);
// 第二步:把所有参数名和参数值串在一起
StringBuilder paramNameValue = new StringBuilder();
for (String paramName : paramNames) {
String val = SignConfig.wrapVal(param.get(paramName));
paramNameValue.append(paramName).append(val);
}
// 第三步:使用MD5/HMAC加密
String source = paramNameValue.toString();
byte[] bytes = signEncipher.encrypt(source, secret);
// 第四步:把二进制转化为大写的十六进制
return byte2hex(bytes).toUpperCase();
} }
} }

@ -2,6 +2,7 @@ package com.gitee.sop.storyweb.config;
import com.gitee.sop.servercommon.bean.ServiceConfig; import com.gitee.sop.servercommon.bean.ServiceConfig;
import com.gitee.sop.servercommon.configuration.AlipayServiceConfiguration; import com.gitee.sop.servercommon.configuration.AlipayServiceConfiguration;
import com.gitee.sop.servercommon.configuration.TaobaoServiceConfiguration;
import com.gitee.sop.servercommon.swagger.SwaggerSupport; import com.gitee.sop.servercommon.swagger.SwaggerSupport;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import springfox.documentation.swagger2.annotations.EnableSwagger2; import springfox.documentation.swagger2.annotations.EnableSwagger2;
@ -11,7 +12,7 @@ import springfox.documentation.swagger2.annotations.EnableSwagger2;
* @author tanghc * @author tanghc
*/ */
@Configuration @Configuration
public class OpenServiceConfig extends AlipayServiceConfiguration { public class OpenServiceConfig extends TaobaoServiceConfiguration {
static { static {
ServiceConfig.getInstance().getI18nModules().add("i18n/isp/goods_error"); ServiceConfig.getInstance().getI18nModules().add("i18n/isp/goods_error");

@ -0,0 +1,45 @@
package com.gitee.sop.storyweb.controller;
import com.gitee.sop.servercommon.annotation.ApiAbility;
import com.gitee.sop.storyweb.controller.param.StoryParam;
import com.gitee.sop.storyweb.controller.result.StoryResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
*
* @author tanghc
*/
@RestController
@Slf4j
// 注解放在这里,表示类中的方法都具备接口开放能力
@ApiAbility
public class TaobaoController {
@RequestMapping("/order/get")
public StoryResult get(@RequestParam String data) {
StoryResult story = new StoryResult();
story.setId(1L);
story.setName(data);
return story;
}
@RequestMapping("/order/save")
public StoryResult save(StoryParam param) {
StoryResult story = new StoryResult();
story.setId((long) param.getId());
story.setName(param.getName());
return story;
}
@RequestMapping("/order/json")
public StoryResult json(@RequestBody StoryParam param) {
StoryResult story = new StoryResult();
story.setId((long) param.getId());
story.setName(param.getName());
return story;
}
}
Loading…
Cancel
Save