1.RSA、加密加签、密钥

1.对称加密

  • 不安全,一旦一方拥有密钥即可自由通信

支付宝公钥和私钥的区别 支付宝私钥的作用_开发语言

2.非对称加密

  • 通过4把钥匙来保证整个通信的安全性,使用RSA加密算法实现

支付宝公钥和私钥的区别 支付宝私钥的作用_支付宝公钥和私钥的区别_02

  • 公钥、私钥
  • 相对概念,公私性是相对于生成者来说的,保存在生产者手里的就是私钥,生成者发布出去的就是公钥
  • 加密和签名
  • 我们使用一对公私钥中的一个密钥来对数据进行加密,而使用另一个密钥来进行解密的技术 公钥和私钥都可以用来加密,也都可以用来解密。 但这个加解密必须是一对密钥之间的互相加解密,否则不能成功。
  • 加密的目的是:为了确保数据传输过程中的不可读性,就是不想让别人看到。
  • 签名和验签
    支付宝为了验证请求的数据是否商户本人发的, 商户为了验证响应的数据是否支付宝发的

2.集成支付宝

1.沙箱环境配置公私钥

支付宝公钥和私钥的区别 支付宝私钥的作用_java_03

支付宝公钥和私钥的区别 支付宝私钥的作用_开发语言_04

3.支付流程图

支付宝公钥和私钥的区别 支付宝私钥的作用_开发语言_05

4.代码实现

<dependency>
       <groupId>com.alipay.sdk</groupId>
       <artifactId>alipay-sdk-java</artifactId>
       <version>4.34.71.ALL</version>
    </dependency>
// alipayConfig
@Configuration
@ConfigurationProperties(prefix = "alipay.config")
public class AliPayClientConfig {
    @Setter
    private String url;
    @Setter
    private String appId;
    @Setter
    private String alipayPublicKey;
    @Setter
    private String privateKey;

    @Bean
    public AlipayClient alipayClient() throws AlipayApiException {
        AlipayConfig alipayConfig = new AlipayConfig();
        // 支付宝网关
        alipayConfig.setServerUrl(url);
        // APPID
        alipayConfig.setAppId(appId);
        // 开发者私钥
        alipayConfig.setPrivateKey(privateKey);
        // 参数返回格式,只支持 JSON(固定)
        alipayConfig.setFormat(AlipayConstants.FORMAT_JSON);
        // 编码集,支持 GBK/UTF-8
        alipayConfig.setCharset(AlipayConstants.CHARSET_UTF8);
        // 支付宝公钥,由支付宝生成
        alipayConfig.setAlipayPublicKey(alipayPublicKey);
        // 生成签名字符串所使用的签名算法类型,目前支持 RSA2 算法
        alipayConfig.setSignType(AlipayConstants.SIGN_TYPE_RSA2);
        //构造client
        return new DefaultAlipayClient(alipayConfig);
    }
}
# 支付配置
alipay:
  config:
    url: https://openapi.alipaydev.com/gateway.do
    appId: ***
    alipayPublicKey: ***
    privateKey: ***
    returnUrl: http://order.dreammall.com/listWithItem.html 
    notifyUrl: https://k24p635902.imdo.co/payed/notify
  • controller
@Controller
@Slf4j
public class OrderPayWebController {
    @Autowired
    private OrderService orderService;

    @Value("${alipay.config.alipayPublicKey}")
    @Setter
    @Getter
    public String alipayPublicKey;

    /**
     * 跳转到支付宝收银页面,等待付款
     *
     * @param orderSn
     * @return
     */
    @ResponseBody
    @GetMapping(value = "/aliPayOrder", produces = "text/html")
    public String aliPayOrder(@RequestParam("orderSn") String orderSn) throws AlipayApiException {
        log.info("订单等待付款:orderSn={}", orderSn);
        AlipayTradePagePayResponse response = orderService.aliPayOrder(orderSn);
        return response.getBody();
    }

    /**
     * 付款成功,跳转回会员信息页
     *
     * @param pageNum
     * @param pageSize
     * @param model
     * @return
     */
    @GetMapping("/listWithItem.html")
    public String listWithItem(@RequestParam(value = "pageNum", required = false, defaultValue = "0") Integer pageNum,
                               @RequestParam(value = "pageSize", required = false, defaultValue = "10") Integer pageSize,
                               Model model) {
        PageUtils orderInfo = orderService.listWithItem(pageNum, pageSize);
        model.addAttribute("orders", orderInfo);
        return "list";
    }

    /**
     * 付款成功,异步通知外网地址,修改订单状态
     * 1.购物车redis删除
     * 2.库存数没减
     */
    @PostMapping("/payed/notify")
    @ResponseBody
    public String handleAliPayed(@RequestParam Map<String, String> prams) {
        // todo 坑 用requestBody接收实体失败 内网穿透无效 后面有时间再弄
        log.info("支付成功,接收到异步通知,prams={}", prams);
        String result = "failure";
        try {
            boolean signVerified = AlipaySignature.rsaCheckV1(prams, alipayPublicKey, AlipayConstants.CHARSET_UTF8, AlipayConstants.SIGN_TYPE_RSA2);  //调用SDK验证签名
            // 验签失败
            if (!signVerified) {
                return result;
            }
            PayAsyncVo asyncVo = JSONObject.parseObject(JSONObject.toJSONString(prams), PayAsyncVo.class);
            return orderService.handleAliPayed(asyncVo);
        } catch (AlipayApiException e) {
            log.error("调用支付宝时出现异常", e);
            return result;
        }
    }
}
  • service
/**
     * 跳转到支付宝支付页面
     *
     * @param orderSn
     * @return
     */
    @Override
    public AlipayTradePagePayResponse aliPayOrder(String orderSn) throws AlipayApiException {
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        AlipayTradePagePayResponse response = new AlipayTradePagePayResponse();
        // 异步通知地址 修改订单状态为已支付
        request.setNotifyUrl(notifyUrl);
        // 支付成功跳转地址
        request.setReturnUrl(returnUrl);
        JSONObject bizContent = new JSONObject();
        // 商户订单号
        Order order = getOne(Wrappers.<Order>lambdaQuery().eq(Order::getOrderSn, orderSn));
        // 订单标题
        List<OrderItem> orderItems = orderItemService.list(Wrappers.<OrderItem>lambdaQuery().eq(OrderItem::getOrderSn, orderSn));
        OrderItem orderItem = orderItems.get(0);

        bizContent.put("out_trade_no", orderSn);
        // 交易金额 保留2位小数(支付宝要求)
        bizContent.put("total_amount", order.getPayAmount().setScale(2, BigDecimal.ROUND_UP).toString());
        // 订单标题
        bizContent.put("subject", orderItem.getSkuName());
        // 销售产品码
        bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");
        // 关单时间 超过多少分钟
        bizContent.put("timeout_express", "2m");
        request.setBizContent(bizContent.toString());
        response = alipayClient.pageExecute(request);
        return response;
    }

    /**
     * 支付成功后显示用户订单信息
     *
     * @param pageNum
     * @return pageSize
     */
    @Override
    public PageUtils listWithItem(Integer pageNum, Integer pageSize) {
        ThreadLocal<MemberResponseVo> user = LoginUserInterceptor.loginUser;
        Page<Order> orderPage = baseMapper.selectPage(new Page<>(pageNum, pageSize), Wrappers.<Order>lambdaQuery().eq(Order::getMemberId, user.get().getId()));

        List<Order> orderList = orderPage.getRecords().stream().map(order -> {
            List<OrderItem> orderItems = orderItemService.list(Wrappers.<OrderItem>lambdaQuery().eq(OrderItem::getOrderSn, order.getOrderSn()));
            order.setOrderItemEntityList(orderItems);
            return order;
        }).collect(Collectors.toList());

        orderPage.setRecords(orderList);

        return new PageUtils(orderPage);
    }

    /**
     * 支付成功异步回调修改订单状态真正扣减库存数
     * @param payAsyncVo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String handleAliPayed(PayAsyncVo payAsyncVo) {
        MemberResponseVo memberResponseVo = LoginUserInterceptor.loginUser.get();
        //保存交易流水信息
        PaymentInfo paymentInfo = new PaymentInfo();
        paymentInfo.setOrderSn(payAsyncVo.getOutTradeNo());
        paymentInfo.setAlipayTradeNo(payAsyncVo.getTradeNo());
        paymentInfo.setTotalAmount(new BigDecimal(payAsyncVo.getBuyerPayAmount()));
        paymentInfo.setSubject(payAsyncVo.getBody());
        paymentInfo.setPaymentStatus(payAsyncVo.getTradeStatus());
        paymentInfo.setCreateTime(new Date());
        paymentInfo.setCallbackTime(payAsyncVo.getNotifyTime());
        //添加到数据库中
        this.paymentInfoService.save(paymentInfo);

        //修改订单状态
        String tradeStatus = payAsyncVo.getTradeStatus();

        if (tradeStatus.equals("TRADE_SUCCESS") || tradeStatus.equals("TRADE_FINISHED")) {
            //支付成功状态
            String orderSn = payAsyncVo.getOutTradeNo(); //获取订单号
            update(Wrappers.<Order>lambdaUpdate().eq(Order::getOrderSn, orderSn).set(Order::getStatus, OrderStatusEnum.PAYED.getCode()));
            // task_detail修改状态
            // 扣减库存数
            wareFeignService.paySucceedUnStock(orderSn);
        }
        return "success";
    }
@Configuration
public class LoginUserInterceptor implements HandlerInterceptor {
    public static ThreadLocal<MemberResponseVo> loginUser = new ThreadLocal<>();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Object attribute = request.getSession().getAttribute(AuthConstant.LOGIN_USER);

        String uri = request.getRequestURI();
        AntPathMatcher antPathMatcher = new AntPathMatcher();
        boolean match = antPathMatcher.match("/order/order/**", uri);
        // 拦截器需要将异步回调路径放开
        if (antPathMatcher.match("/payed/notify", uri)){
            return true;
        }
        if (match) {
            return true;
        }
        if (Objects.nonNull(attribute) && attribute instanceof MemberResponseVo) {
            MemberResponseVo vo = (MemberResponseVo) attribute;
            loginUser.set(vo);
            return true;
        }
        request.getSession().setAttribute("msg", "请先进行登录");
        response.sendRedirect("http://auth.dreammall.com/login.html");
        return false;
    }
}
  • 内网穿透 配合nginx实现

支付宝公钥和私钥的区别 支付宝私钥的作用_ide_06