parent
4bcdf212c5
commit
296fafef74
@ -0,0 +1,7 @@
|
||||
package au.com.royalpay.payment.manage.shopify.auth.domain;
|
||||
|
||||
public class ShopifyRequestVerifyException extends RuntimeException{
|
||||
public ShopifyRequestVerifyException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package au.com.royalpay.payment.manage.shopify.auth.domain.entity;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ShopifyCommonParameter {
|
||||
private String shop;
|
||||
private String code;
|
||||
private String state;
|
||||
private String hmac;
|
||||
private String host;
|
||||
private String timestamp;
|
||||
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package au.com.royalpay.payment.manage.shopify.auth.domain.service;
|
||||
|
||||
import au.com.royalpay.payment.manage.shopify.auth.domain.entity.ShopifyCommonParameter;
|
||||
import au.com.royalpay.payment.manage.shopify.support.HmacVerificationUtil;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class ShopifyRequestValidator {
|
||||
|
||||
@Value("${shopify.auth.apiSecretKey}")
|
||||
private String clientSecret;
|
||||
|
||||
public Boolean valid(ShopifyCommonParameter parameter) {
|
||||
StringBuilder message =new StringBuilder();
|
||||
message.append("code=").append(parameter.getCode())
|
||||
.append("&host=").append(parameter.getHost())
|
||||
.append("&shop=").append(parameter.getShop())
|
||||
.append("&state=").append(parameter.getState())
|
||||
.append("×tamp=").append(parameter.getTimestamp());
|
||||
return HmacVerificationUtil.hmacSHA256(message.toString(),clientSecret,parameter.getHmac());
|
||||
}
|
||||
|
||||
public boolean verifyPermission(String shopifyStoreHost, String hmac, String timestamp) {
|
||||
StringBuilder message =new StringBuilder();
|
||||
message.append("shop=").append(shopifyStoreHost)
|
||||
.append("×tamp=").append(timestamp);
|
||||
return HmacVerificationUtil.hmacSHA256(message.toString(),clientSecret,hmac);
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package au.com.royalpay.payment.manage.shopify.auth.web.command;
|
||||
|
||||
import au.com.royalpay.payment.manage.shopify.auth.domain.entity.ShopifyCommonParameter;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Pattern;
|
||||
|
||||
@Data
|
||||
public class ShopifyVerifyRequest {
|
||||
|
||||
@NotBlank(message = "Code can not blank")
|
||||
private String code;
|
||||
|
||||
@NotBlank(message = "hmac can not blank")
|
||||
private String hmac;
|
||||
|
||||
@NotBlank(message = "host can not blank")
|
||||
private String host;
|
||||
|
||||
@NotBlank(message = "Shop can not blank")
|
||||
@Pattern(regexp = "^[a-zA-Z0-9][a-zA-Z0-9\\-]*\\.myshopify\\.com", message = "Shop hostname is invalid")
|
||||
private String shop;
|
||||
|
||||
@NotBlank(message = "state can not blank")
|
||||
private String state;
|
||||
|
||||
@NotBlank(message = "timestamp can not blank")
|
||||
private String timestamp;
|
||||
|
||||
public ShopifyCommonParameter build() {
|
||||
return ShopifyCommonParameter.builder()
|
||||
.code(code)
|
||||
.hmac(hmac)
|
||||
.host(host)
|
||||
.shop(shop)
|
||||
.state(state)
|
||||
.timestamp(timestamp)
|
||||
.build();
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
package au.com.royalpay.payment.manage.shopify.support;
|
||||
|
||||
import org.apache.commons.codec.digest.HmacAlgorithms;
|
||||
import org.apache.commons.codec.digest.HmacUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.bouncycastle.crypto.RuntimeCryptoException;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import javax.xml.bind.annotation.adapters.HexBinaryAdapter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.Security;
|
||||
import java.util.Locale;
|
||||
|
||||
public class HmacVerificationUtil {
|
||||
|
||||
public static boolean checkParameters(String message, String secret, String hmac) {
|
||||
try {
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
SecretKey secretKey = new SecretKeySpec(secret.getBytes("UTF8"), "HmacSHA256");
|
||||
Mac mac = Mac.getInstance(secretKey.getAlgorithm());
|
||||
mac.init(secretKey);
|
||||
byte[] digest = mac.doFinal(message.getBytes("UTF-8"));
|
||||
String marshal = new HexBinaryAdapter().marshal(digest).toLowerCase(Locale.ROOT);
|
||||
return StringUtils.equals(marshal, hmac);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeCryptoException("加密异常");
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hmacSHA256(String input, String key, String hmac) {
|
||||
String encode = encode(input, key, HmacAlgorithms.HMAC_SHA_256);
|
||||
return StringUtils.equals(encode, hmac);
|
||||
}
|
||||
|
||||
private static String encode(String input, String key, HmacAlgorithms algorithm) {
|
||||
Mac mac = HmacUtils.getInitializedMac(algorithm, key.getBytes(StandardCharsets.UTF_8));
|
||||
byte[] content = input.getBytes(StandardCharsets.UTF_8);
|
||||
byte[] signResult = mac.doFinal(content);
|
||||
return bytesToHex(signResult);
|
||||
}
|
||||
|
||||
private static String bytesToHex(byte[] hash) {
|
||||
StringBuilder hexString = new StringBuilder();
|
||||
for (byte b : hash) {
|
||||
String hex = Integer.toHexString(0xff & b);
|
||||
if (hex.length() == 1) {
|
||||
hexString.append('0');
|
||||
}
|
||||
hexString.append(hex);
|
||||
}
|
||||
return hexString.toString();
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package au.com.royalpay.payment.manage.shopify.auth.domain.service;
|
||||
|
||||
import au.com.royalpay.payment.manage.shopify.auth.domain.entity.ShopifyCommonParameter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@Slf4j
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
@ActiveProfiles({"dev", "alipay", "bestpay", "jd", "wechat", "rpay", "yeepay", "rppaysvc", "common", "alipayplusaps"})
|
||||
class ShopifyRequestValidatorTest {
|
||||
|
||||
@Autowired
|
||||
private ShopifyRequestValidator shopifyRequestValidator;
|
||||
|
||||
@Test
|
||||
public void shopifyRequestValidatorTest() {
|
||||
ShopifyCommonParameter parameter = ShopifyCommonParameter.builder()
|
||||
.code("4618ddc9da54cee7be06b35f49c72349")
|
||||
.host("Z2Vlay10ZXN0LXNob3AubXlzaG9waWZ5LmNvbS9hZG1pbg")
|
||||
.shop("geek-test-shop.myshopify.com")
|
||||
.timestamp("1643097047")
|
||||
.state("1643097021")
|
||||
.hmac("e7884f623057afd700b27ba8a5b7529a3f2a2943d2931d73fb82c57f2cf0baaa")
|
||||
.build();
|
||||
Boolean valid = shopifyRequestValidator.valid(parameter);
|
||||
log.warn(String.format("---------------------result: [%s]-------------",valid));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShopifyDomain() {
|
||||
String shop = "exampleshop.myshopify.com";
|
||||
|
||||
boolean matches = Pattern.matches("^[a-zA-Z0-9][a-zA-Z0-9\\-]*\\.myshopify\\.com", shop);
|
||||
|
||||
log.warn(String.format("---------------------matches: [%s]-------------",matches));
|
||||
}
|
||||
}
|
Loading…
Reference in new issue