| @@ -147,7 +147,7 @@ public class ShiroConfig { | |||||
| filterChainDefinitionMap.put("/wxDeviceScreenAd/**", "anon"); | filterChainDefinitionMap.put("/wxDeviceScreenAd/**", "anon"); | ||||
| // filterChainDefinitionMap.put("/role/**", "corsFilter,token"); | // filterChainDefinitionMap.put("/role/**", "corsFilter,token"); | ||||
| //商场初始化init | //商场初始化init | ||||
| // filterChainDefinitionMap.put("/wxProjectConfig/**", "anon"); | |||||
| filterChainDefinitionMap.put("/wxProjectConfig/**", "anon"); | |||||
| // //test | // //test | ||||
| // filterChainDefinitionMap.put("/merchantPoi/spuSync", "anon"); | // filterChainDefinitionMap.put("/merchantPoi/spuSync", "anon"); | ||||
| @@ -10,10 +10,13 @@ import com.iformall.controller.base.BaseController; | |||||
| import com.iformall.domain.po.*; | import com.iformall.domain.po.*; | ||||
| import com.iformall.domain.po.base.TenantEntity; | import com.iformall.domain.po.base.TenantEntity; | ||||
| import com.iformall.domain.vo.WxWeappInfo; | import com.iformall.domain.vo.WxWeappInfo; | ||||
| import com.iformall.douyin.pay.TtPayService; | |||||
| import com.iformall.douyin.payv2.request.CallBackSettingsRequest; | |||||
| import com.iformall.enums.*; | import com.iformall.enums.*; | ||||
| import com.iformall.service.*; | import com.iformall.service.*; | ||||
| import com.iformall.shiro.PasswordHelper; | import com.iformall.shiro.PasswordHelper; | ||||
| import com.iformall.utils.Constant; | import com.iformall.utils.Constant; | ||||
| import com.iformall.utils.MaUtil; | |||||
| import io.swagger.annotations.Api; | import io.swagger.annotations.Api; | ||||
| import io.swagger.annotations.ApiOperation; | import io.swagger.annotations.ApiOperation; | ||||
| import org.apache.commons.lang3.StringUtils; | import org.apache.commons.lang3.StringUtils; | ||||
| @@ -94,6 +97,9 @@ public class WxProjectConfigController extends BaseController { | |||||
| @Autowired | @Autowired | ||||
| private WechatWebProperties wechatWebProperties; | private WechatWebProperties wechatWebProperties; | ||||
| @Autowired | |||||
| private MaUtil maUtil; | |||||
| @Autowired | @Autowired | ||||
| @Qualifier("openRedisTemplate") | @Qualifier("openRedisTemplate") | ||||
| RedisTemplate<String, String> openRedisTemplate; | RedisTemplate<String, String> openRedisTemplate; | ||||
| @@ -774,4 +780,74 @@ public class WxProjectConfigController extends BaseController { | |||||
| } | } | ||||
| } | } | ||||
| @ApiOperation("获取抖音支付2.0 回调接口配置") | |||||
| @GetMapping("/ttcallback/query/settings") | |||||
| @SystemControllerLog(description = "") | |||||
| @TenantIgnore | |||||
| public ResultData ttcallbackQuerySettings(String appid) { | |||||
| logger.debug("[" + getIpAddr() + "] WxProjectConfigController::ttcallbackQuerySettings"); | |||||
| try { | |||||
| WxAppinfo appinfo = wxAppinfoService.getByAppId(appid); | |||||
| if(appinfo == null){ | |||||
| return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(),"未找到对应的小程序"); | |||||
| } | |||||
| if(!EnumAppPlat.TOUTIAO.getCode().equals(appinfo.getPlat()) || !EnumAppType.C.getCode().equals(appinfo.getType())){ | |||||
| return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(),"该小程序不支持"); | |||||
| } | |||||
| WxPayAccount payAccount = wxPayAccountService.getById(appinfo.getPayId()); | |||||
| if(payAccount == null){ | |||||
| return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(),"未找到对应的支付数据"); | |||||
| } | |||||
| TtPayService ttPayService = maUtil.getTtPayService(appinfo, payAccount); | |||||
| CallBackSettingsRequest callBackSettingsRequest = ttPayService.querySettings(); | |||||
| return new ResultData(callBackSettingsRequest); | |||||
| }catch (Exception e){ | |||||
| logger.error(e.getMessage(),e); | |||||
| return new ResultData(ErrorCode.SYS_SERVER_ERROR); | |||||
| } | |||||
| } | |||||
| @ApiOperation("配置抖音支付2.0 回调接口") | |||||
| @PostMapping("/ttcallback/settings") | |||||
| @SystemControllerLog(description = "商场集团-更新") | |||||
| @TenantIgnore | |||||
| public ResultData ttcallbackSettings(@RequestBody Map<String, String> map) { | |||||
| logger.debug("[" + getIpAddr() + "] WxProjectConfigController::ttcallbackSettings"); | |||||
| String appid = map.get("appid"); | |||||
| String create_order_callback = map.get("create_order_callback"); | |||||
| String refund_callback = map.get("refund_callback"); | |||||
| String delivery_qrcode_redirect = map.get("delivery_qrcode_redirect"); | |||||
| if(StringUtils.isBlank(appid) || StringUtils.isBlank(create_order_callback) | |||||
| || StringUtils.isBlank(refund_callback)){ | |||||
| return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); | |||||
| } | |||||
| try { | |||||
| WxAppinfo appinfo = wxAppinfoService.getByAppId(appid); | |||||
| if(appinfo == null){ | |||||
| return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(),"未找到对应的小程序"); | |||||
| } | |||||
| if(!EnumAppPlat.TOUTIAO.getCode().equals(appinfo.getPlat()) || !EnumAppType.C.getCode().equals(appinfo.getType())){ | |||||
| return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(),"该小程序不支持"); | |||||
| } | |||||
| WxPayAccount payAccount = wxPayAccountService.getById(appinfo.getPayId()); | |||||
| if(payAccount == null){ | |||||
| return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(),"未找到对应的支付数据"); | |||||
| } | |||||
| TtPayService ttPayService = maUtil.getTtPayService(appinfo, payAccount); | |||||
| CallBackSettingsRequest request = new CallBackSettingsRequest(); | |||||
| request.setCreateOrderCallback(create_order_callback); | |||||
| request.setRefundCallback(refund_callback); | |||||
| request.setDeliveryQrcodeRedirect(delivery_qrcode_redirect); | |||||
| boolean b = ttPayService.callbackSettings(request); | |||||
| if(b){ | |||||
| return new ResultData(); | |||||
| }else{ | |||||
| return new ResultData(ErrorCode.SYS_SERVER_ERROR); | |||||
| } | |||||
| }catch (Exception e){ | |||||
| logger.error(e.getMessage(),e); | |||||
| return new ResultData(ErrorCode.SYS_SERVER_ERROR); | |||||
| } | |||||
| } | |||||
| } | } | ||||
| @@ -1,7 +1,9 @@ | |||||
| package com.iformall.controller; | package com.iformall.controller; | ||||
| import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | ||||
| import com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader; | |||||
| import com.github.pagehelper.PageInfo; | import com.github.pagehelper.PageInfo; | ||||
| import com.iformall.annotation.AuthIgnore; | |||||
| import com.iformall.common.ErrorCode; | import com.iformall.common.ErrorCode; | ||||
| import com.iformall.common.IdWorker; | import com.iformall.common.IdWorker; | ||||
| import com.iformall.common.Result; | import com.iformall.common.Result; | ||||
| @@ -16,6 +18,7 @@ import com.iformall.domain.vo.WxOrderCouponPressVo; | |||||
| import com.iformall.domain.vo.WxOrderCouponVo; | import com.iformall.domain.vo.WxOrderCouponVo; | ||||
| import com.iformall.enums.*; | import com.iformall.enums.*; | ||||
| import com.iformall.exception.MallinkException; | import com.iformall.exception.MallinkException; | ||||
| import com.iformall.interceptor.BodyReaderHttpServletRequestWrapper; | |||||
| import com.iformall.service.*; | import com.iformall.service.*; | ||||
| import com.iformall.service.order.OrderFactory; | import com.iformall.service.order.OrderFactory; | ||||
| import com.iformall.service.order.entity.WxComposeOrder; | import com.iformall.service.order.entity.WxComposeOrder; | ||||
| @@ -34,10 +37,8 @@ import org.springframework.beans.factory.annotation.Qualifier; | |||||
| import org.springframework.data.redis.core.RedisTemplate; | import org.springframework.data.redis.core.RedisTemplate; | ||||
| import org.springframework.web.bind.annotation.*; | import org.springframework.web.bind.annotation.*; | ||||
| import java.util.ArrayList; | |||||
| import java.util.Date; | |||||
| import java.util.List; | |||||
| import java.util.Map; | |||||
| import javax.servlet.http.HttpServletRequest; | |||||
| import java.util.*; | |||||
| @RestController | @RestController | ||||
| @RequestMapping("/api/order/") | @RequestMapping("/api/order/") | ||||
| @@ -138,27 +139,42 @@ public class WxOrderController extends BaseController { | |||||
| list.add(dto); | list.add(dto); | ||||
| return wxOrderService.composeSaveOrder(false,EnumComposeOrder.SINGLE,list,memberId,getPayWay(),getTenantInfo()); | return wxOrderService.composeSaveOrder(false,EnumComposeOrder.SINGLE,list,memberId,getPayWay(),getTenantInfo()); | ||||
| } | } | ||||
| @AuthIgnore | |||||
| @ApiOperation(value = "抖音支付2.0与下单回调推送订单", notes = "{\"couponChannelId\":\"String\",\"couponId\":\"String\",\"press\":\"String\",\"orderGroupId\":\"String\",\"formId\":\"String\"}") | @ApiOperation(value = "抖音支付2.0与下单回调推送订单", notes = "{\"couponChannelId\":\"String\",\"couponId\":\"String\",\"press\":\"String\",\"orderGroupId\":\"String\",\"formId\":\"String\"}") | ||||
| @PostMapping("douyinPushOrder") | @PostMapping("douyinPushOrder") | ||||
| public ResultData douyinPushOrder(@RequestBody Map param) { | |||||
| logger.info("save douyinPushOrder:"+param); | |||||
| Long memberId; | |||||
| try { | |||||
| memberId = getMemberId(); | |||||
| } catch (Exception e) { | |||||
| return new ResultData(Result.ERROR,e.getMessage()); | |||||
| } | |||||
| List<PlatPushOrderSaveDto> list = new ArrayList<>(); | |||||
| PlatPushOrderSaveDto dto = new PlatPushOrderSaveDto(); | |||||
| /** | |||||
| * TODO 从抖音推送的订单中取信息,每个订单里面有extParam,用来放第三方平台匹配的参数信息 | |||||
| * 注意,wx_batch_order中要存allExtParam, wx_order,wx_coupon_order中存储每个订单的参数信息,需要自己根据总参数信息进行拆分 | |||||
| */ | |||||
| list.add(dto); | |||||
| String allExtParam = "[]"; | |||||
| return wxOrderService.platPushSaveOrder(false,EnumComposeOrder.ONE_NUMBER_ORDER_BATCH,allExtParam,list,memberId,getPayWay(),getTenantInfo()); | |||||
| public Map<String,Object> douyinPushOrder(HttpServletRequest request) { | |||||
| SignatureHeader header = new SignatureHeader(); | |||||
| header.setTimeStamp(request.getHeader("Byte-Timestamp")); | |||||
| header.setNonce(request.getHeader("Byte-Nonce-Str")); | |||||
| header.setSigned(request.getHeader("Byte-Signature")); | |||||
| logger.info("支付2.0预下单回调---header{}"+header.toString()); | |||||
| String body = ((BodyReaderHttpServletRequestWrapper) request).getBody(); | |||||
| logger.info("支付2.0预下单回调---body{}"+body); | |||||
| Map<String, Object> map = new HashMap(); | |||||
| map.put("err_no",1000); | |||||
| map.put("err_tips","库存不足"); | |||||
| return map; | |||||
| // Long memberId; | |||||
| // try { | |||||
| // memberId = getMemberId(); | |||||
| // } catch (Exception e) { | |||||
| // return new ResultData(Result.ERROR,e.getMessage()); | |||||
| // } | |||||
| // | |||||
| // List<PlatPushOrderSaveDto> list = new ArrayList<>(); | |||||
| // PlatPushOrderSaveDto dto = new PlatPushOrderSaveDto(); | |||||
| // /** | |||||
| // * TODO 从抖音推送的订单中取信息,每个订单里面有extParam,用来放第三方平台匹配的参数信息 | |||||
| // * 注意,wx_batch_order中要存allExtParam, wx_order,wx_coupon_order中存储每个订单的参数信息,需要自己根据总参数信息进行拆分 | |||||
| // */ | |||||
| // list.add(dto); | |||||
| // String allExtParam = "[]"; | |||||
| // return wxOrderService.platPushSaveOrder(false,EnumComposeOrder.ONE_NUMBER_ORDER_BATCH,allExtParam,list,memberId,getPayWay(),getTenantInfo()); | |||||
| } | } | ||||
| @@ -700,4 +716,25 @@ public class WxOrderController extends BaseController { | |||||
| return new ResultData(refundOrder); | return new ResultData(refundOrder); | ||||
| } | } | ||||
| @AuthIgnore | |||||
| @ApiOperation(value = "抖音支付2.0与退款回调推送订单", notes = "{\"couponChannelId\":\"String\",\"couponId\":\"String\",\"press\":\"String\",\"orderGroupId\":\"String\",\"formId\":\"String\"}") | |||||
| @PostMapping("douyinRefundOrder") | |||||
| public Map<String,Object> douyinRefundOrder(HttpServletRequest request) { | |||||
| SignatureHeader header = new SignatureHeader(); | |||||
| header.setTimeStamp(request.getHeader("Byte-Timestamp")); | |||||
| header.setNonce(request.getHeader("Byte-Nonce-Str")); | |||||
| header.setSigned(request.getHeader("Byte-Signature")); | |||||
| logger.info("支付2.0预下单回调---header{}"+header.toString()); | |||||
| String body = ((BodyReaderHttpServletRequestWrapper) request).getBody(); | |||||
| logger.info("支付2.0预下单回调---body{}"+body); | |||||
| Map<String, Object> map = new HashMap(); | |||||
| map.put("err_no",1001); | |||||
| map.put("err_tips","未找到支付信息"); | |||||
| return map; | |||||
| } | |||||
| } | } | ||||
| @@ -74,7 +74,12 @@ public abstract class BaseTtPayServiceImpl implements TtPayService { | |||||
| public boolean callbackSettings(CallBackSettingsRequest request) throws TtPayException { | public boolean callbackSettings(CallBackSettingsRequest request) throws TtPayException { | ||||
| String url = String.format("%s/api/apps/trade/v2/settings", this.getPayBaseUrl()); | String url = String.format("%s/api/apps/trade/v2/settings", this.getPayBaseUrl()); | ||||
| String response = this.postV2(url, GSON.toJson(request)); | String response = this.postV2(url, GSON.toJson(request)); | ||||
| return GSON.fromJson(response, BaseTtPayResult.class).isSuccess(); | |||||
| BaseTtPayResult baseTtPayResult = GSON.fromJson(response, BaseTtPayResult.class); | |||||
| if(baseTtPayResult.isSuccess()){ | |||||
| return true; | |||||
| }else{ | |||||
| throw new TtPayException(baseTtPayResult.getErrTips()); | |||||
| } | |||||
| } | } | ||||
| @Override | @Override | ||||
| @@ -174,7 +179,12 @@ public abstract class BaseTtPayServiceImpl implements TtPayService { | |||||
| public boolean pushDelivery(TtOrderPushDeliveryRequest request) throws TtPayException{ | public boolean pushDelivery(TtOrderPushDeliveryRequest request) throws TtPayException{ | ||||
| String url = String.format("%s/api/apps/trade/v2/push_delivery", this.getPayBaseUrl()); | String url = String.format("%s/api/apps/trade/v2/push_delivery", this.getPayBaseUrl()); | ||||
| String response = this.postV2(url, GSON.toJson(request)); | String response = this.postV2(url, GSON.toJson(request)); | ||||
| return GSON.fromJson(response, BaseTtPayResult.class).isSuccess(); | |||||
| BaseTtPayResult baseTtPayResult = GSON.fromJson(response, BaseTtPayResult.class); | |||||
| if(baseTtPayResult.isSuccess()){ | |||||
| return true; | |||||
| }else{ | |||||
| throw new TtPayException(baseTtPayResult.getErrTips()); | |||||
| } | |||||
| } | } | ||||
| @@ -209,7 +219,12 @@ public abstract class BaseTtPayServiceImpl implements TtPayService { | |||||
| public boolean merchantAuditCallback(TtRefundAuditMsgRequest request) throws TtPayException{ | public boolean merchantAuditCallback(TtRefundAuditMsgRequest request) throws TtPayException{ | ||||
| String url = String.format("%s/api/apps/trade/v2/merchant_audit_callback", this.getPayBaseUrl()); | String url = String.format("%s/api/apps/trade/v2/merchant_audit_callback", this.getPayBaseUrl()); | ||||
| String response = this.postV2(url, GSON.toJson(request)); | String response = this.postV2(url, GSON.toJson(request)); | ||||
| return GSON.fromJson(response, BaseTtPayResult.class).isSuccess(); | |||||
| BaseTtPayResult baseTtPayResult = GSON.fromJson(response, BaseTtPayResult.class); | |||||
| if(baseTtPayResult.isSuccess()){ | |||||
| return true; | |||||
| }else{ | |||||
| throw new TtPayException(baseTtPayResult.getErrTips()); | |||||
| } | |||||
| } | } | ||||
| @Override | @Override | ||||
| @@ -1,7 +1,11 @@ | |||||
| package com.iformall.douyin.payv2.auth; | package com.iformall.douyin.payv2.auth; | ||||
| import com.iformall.douyin.payv2.util.PemUtils; | |||||
| import me.chanjar.weixin.common.error.WxRuntimeException; | import me.chanjar.weixin.common.error.WxRuntimeException; | ||||
| import java.io.ByteArrayInputStream; | |||||
| import java.io.UnsupportedEncodingException; | |||||
| import java.nio.charset.StandardCharsets; | |||||
| import java.security.*; | import java.security.*; | ||||
| import java.util.Base64; | import java.util.Base64; | ||||
| @@ -19,7 +23,7 @@ public class CertificatesVerifier implements Verifier { | |||||
| Signature sign = Signature.getInstance("SHA256withRSA"); | Signature sign = Signature.getInstance("SHA256withRSA"); | ||||
| sign.initVerify(this.apiKey); | sign.initVerify(this.apiKey); | ||||
| sign.update(message); | sign.update(message); | ||||
| return sign.verify(Base64.getDecoder().decode(signature)); | |||||
| return sign.verify(Base64.getDecoder().decode(signature.getBytes(StandardCharsets.UTF_8))); | |||||
| } catch (NoSuchAlgorithmException e) { | } catch (NoSuchAlgorithmException e) { | ||||
| throw new WxRuntimeException("当前Java环境不支持SHA256withRSA", e); | throw new WxRuntimeException("当前Java环境不支持SHA256withRSA", e); | ||||
| } catch (SignatureException e) { | } catch (SignatureException e) { | ||||
| @@ -29,4 +33,40 @@ public class CertificatesVerifier implements Verifier { | |||||
| } | } | ||||
| } | } | ||||
| // public static void main(String[] args) { | |||||
| // String pubKey = "-----BEGIN PUBLIC KEY-----\n" + | |||||
| // "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv8jSFriZ6l5vv0xVcpFJ\n" + | |||||
| // "NxihPh3j6tVKrU2FBythCstyr/CwdpAp9AGXvcaW2x2kKiOMXXaRDo6OysjggsxK\n" + | |||||
| // "5hh1fWDE3ML4Wi5tfAV64pvj8wn5XeHXGKtXcKD/ASQmUGnMKI0g8i2REm3Q7gzy\n" + | |||||
| // "JH35URh+tU8wI2v8mDY9OCZ7Hmu8ImW3pibyYRYK0CEpa31+65gVaTeoaPlqTKR0\n" + | |||||
| // "rwgxZM5nFcXxGtiTsH0O1GAJBqWpyVeOqH19vEVB/bROEb21bf65ZYhac2Z1lzWq\n" + | |||||
| // "MW+/4knIDg6EH3/xZWFPPwAFZgpfkSQES/twPkN/59cZ8SfTwJ84k/KUOApvkihM\n" + | |||||
| // "uQIDAQAB\n" + | |||||
| // "-----END PUBLIC KEY-----"; | |||||
| // String timestamp = "1653906762"; | |||||
| // String nonce = "pztVmu9EhPgCv9Dvw31t68U9WhMcLXCb"; | |||||
| // String httpBody = "{\"err_no\":0,\"data\":{\"create_order_callback\":\"https://ctest.malls.iformall.com/C/api/order/douyinPushOrder\",\"refund_callback\":\"https://ctest.malls.iformall.com/C/api/order/douyinRefundOrder\",\"delivery_qrcode_redirect\":\"\"},\"resp_extra\":{\"logid\":\"202205301832420101581160381B3C09C0\"},\"err_tips\":\"success\"}"; | |||||
| // String signStr = "pZEQga7EpGI+NXEznLNZROViIBxwWaofnlstthQsu8MZiuTRUtool2SQhfLHkXwYzj5O8yj+luTbFUrhTfX+BzvcR3+fGrqMtgqGWp86a1hAg4e4pvoTHd5PAxUGRDb/gGxPoxLDgrS6cLKusdGi6mmwJbERveD9ThNV1RQGQo/BM3BeImr3fYdJ/ZU67iVkP6SEWkqRiEJhnQMaavy/B4LK3xI0A5BhWlGbhGUIqumLT903tIOhofXGA6PQJbDiU38J5EtMj/Z7l6+IXtbA/KO0IWbIZ96KFs6e8ZE6H18Xn7b0J7KDTjTelMt7iXczrLU2/e3QEcfn2/7+7DIRMQ=="; | |||||
| // | |||||
| // StringBuffer buffer = new StringBuffer(); | |||||
| // buffer.append(timestamp).append("\n"); | |||||
| // buffer.append(nonce).append("\n"); | |||||
| // buffer.append(httpBody).append("\n"); | |||||
| // try { | |||||
| // Signature sign = Signature.getInstance("SHA256withRSA"); | |||||
| // sign.initVerify(PemUtils.loadPublicKey(new ByteArrayInputStream(pubKey.getBytes("utf-8")))); | |||||
| // sign.update(buffer.toString().getBytes(StandardCharsets.UTF_8)); | |||||
| // boolean verify = sign.verify(Base64.getDecoder().decode(signStr.getBytes(StandardCharsets.UTF_8))); | |||||
| // System.out.println("-------"+verify); | |||||
| // } catch (NoSuchAlgorithmException e) { | |||||
| // e.printStackTrace(); | |||||
| // } catch (UnsupportedEncodingException e) { | |||||
| // e.printStackTrace(); | |||||
| // } catch (SignatureException e) { | |||||
| // e.printStackTrace(); | |||||
| // } catch (InvalidKeyException e) { | |||||
| // e.printStackTrace(); | |||||
| // } | |||||
| // } | |||||
| } | } | ||||
| @@ -1,10 +1,10 @@ | |||||
| package com.iformall.douyin.payv2.config; | package com.iformall.douyin.payv2.config; | ||||
| import com.github.binarywang.wxpay.v3.util.PemUtils; | |||||
| import com.iformall.douyin.pay.exception.TtPayException; | import com.iformall.douyin.pay.exception.TtPayException; | ||||
| import com.iformall.douyin.payv2.auth.CertificatesVerifier; | import com.iformall.douyin.payv2.auth.CertificatesVerifier; | ||||
| import com.iformall.douyin.payv2.auth.TtPayValidator; | import com.iformall.douyin.payv2.auth.TtPayValidator; | ||||
| import com.iformall.douyin.payv2.auth.Verifier; | import com.iformall.douyin.payv2.auth.Verifier; | ||||
| import com.iformall.douyin.payv2.util.PemUtils; | |||||
| import com.iformall.douyin.payv2.util.TtPayV2HttpClientBuilder; | import com.iformall.douyin.payv2.util.TtPayV2HttpClientBuilder; | ||||
| import jodd.util.ResourcesUtil; | import jodd.util.ResourcesUtil; | ||||
| import lombok.Data; | import lombok.Data; | ||||
| @@ -20,7 +20,7 @@ import java.io.Serializable; | |||||
| */ | */ | ||||
| @Data | @Data | ||||
| @NoArgsConstructor | @NoArgsConstructor | ||||
| public abstract class BaseTtPayResult<T> implements Serializable { | |||||
| public class BaseTtPayResult<T> implements Serializable { | |||||
| /** | /** | ||||
| * 返回状态码. | * 返回状态码. | ||||
| @@ -0,0 +1,89 @@ | |||||
| package com.iformall.douyin.payv2.util; | |||||
| import me.chanjar.weixin.common.error.WxRuntimeException; | |||||
| import sun.misc.BASE64Decoder; | |||||
| import java.io.ByteArrayOutputStream; | |||||
| import java.io.IOException; | |||||
| import java.io.InputStream; | |||||
| import java.security.KeyFactory; | |||||
| import java.security.NoSuchAlgorithmException; | |||||
| import java.security.PrivateKey; | |||||
| import java.security.PublicKey; | |||||
| import java.security.cert.*; | |||||
| import java.security.spec.InvalidKeySpecException; | |||||
| import java.security.spec.PKCS8EncodedKeySpec; | |||||
| import java.security.spec.X509EncodedKeySpec; | |||||
| import java.util.Base64; | |||||
| public class PemUtils { | |||||
| public static PrivateKey loadPrivateKey(InputStream inputStream) { | |||||
| try { | |||||
| ByteArrayOutputStream array = new ByteArrayOutputStream(); | |||||
| byte[] buffer = new byte[1024]; | |||||
| int length; | |||||
| while ((length = inputStream.read(buffer)) != -1) { | |||||
| array.write(buffer, 0, length); | |||||
| } | |||||
| String privateKey = array.toString("utf-8") | |||||
| .replace("-----BEGIN PRIVATE KEY-----", "") | |||||
| .replace("-----END PRIVATE KEY-----", "") | |||||
| .replaceAll("\\s+", ""); | |||||
| KeyFactory kf = KeyFactory.getInstance("RSA"); | |||||
| return kf.generatePrivate( | |||||
| new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey))); | |||||
| } catch (NoSuchAlgorithmException e) { | |||||
| throw new WxRuntimeException("当前Java环境不支持RSA", e); | |||||
| } catch (InvalidKeySpecException e) { | |||||
| throw new WxRuntimeException("无效的密钥格式"); | |||||
| } catch (IOException e) { | |||||
| throw new WxRuntimeException("无效的密钥"); | |||||
| } | |||||
| } | |||||
| public static X509Certificate loadCertificate(InputStream inputStream) { | |||||
| try { | |||||
| CertificateFactory cf = CertificateFactory.getInstance("X509"); | |||||
| X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream); | |||||
| cert.checkValidity(); | |||||
| return cert; | |||||
| } catch (CertificateExpiredException e) { | |||||
| throw new WxRuntimeException("证书已过期", e); | |||||
| } catch (CertificateNotYetValidException e) { | |||||
| throw new WxRuntimeException("证书尚未生效", e); | |||||
| } catch (CertificateException e) { | |||||
| throw new WxRuntimeException("无效的证书", e); | |||||
| } | |||||
| } | |||||
| public static PublicKey loadPublicKey(InputStream inputStream) { | |||||
| try { | |||||
| ByteArrayOutputStream array = new ByteArrayOutputStream(); | |||||
| byte[] buffer = new byte[1024]; | |||||
| int length; | |||||
| while ((length = inputStream.read(buffer)) != -1) { | |||||
| array.write(buffer, 0, length); | |||||
| } | |||||
| String publicKey = array.toString("utf-8") | |||||
| .replace("-----BEGIN PUBLIC KEY-----", "") | |||||
| .replace("-----END PUBLIC KEY-----", "") | |||||
| .replaceAll("\\s+", ""); | |||||
| KeyFactory kf = KeyFactory.getInstance("RSA"); | |||||
| return kf.generatePublic( | |||||
| new X509EncodedKeySpec(new BASE64Decoder().decodeBuffer(publicKey))); | |||||
| } catch (NoSuchAlgorithmException e) { | |||||
| throw new WxRuntimeException("当前Java环境不支持RSA", e); | |||||
| } catch (InvalidKeySpecException e) { | |||||
| throw new WxRuntimeException("无效的密钥格式"); | |||||
| } catch (IOException e) { | |||||
| throw new WxRuntimeException("无效的密钥"); | |||||
| } | |||||
| } | |||||
| } | |||||