简单的支付宝沙箱支付接入以及电脑网站支付示例

支付宝沙箱支付接入流程


1、首先进入支付宝开放平台申请个人开发者账号

2、创建应用,添加电脑网站支付能力

这里我申请的是支付宝网站支付功能。

3、进入支付宝沙箱环境设置接口加签方式我这里设置的是自定义密钥(RSA2)

文档:https://opendocs.alipay.com/common/02kipl

这里我们需要获取我们需要的秘钥:应用公钥、支付宝公钥,还需要记住生成应用公钥的时候我们自己保存的应用私钥,这三个参数,其中应用公钥、支付宝公钥都可以在沙箱账号中查看,应用私钥是自己有的。
其他信息:沙箱应用的appid,以及沙箱账户的商户账号密码,和用户账号密码.方便付款操作。

4、下载sdk

https://opendocs.alipay.com/open/270/106291

修改sdk中的config.php文件
<?php
$config = array (	
		//应用ID,您的APPID,这里是沙箱账户中的appid。
		'app_id' => "",

		//商户私钥,自己生成的私钥
		'merchant_private_key' => "",
		
		//异步通知地址
		'notify_url' => "http://cakephp.com/alipay/aliPayNotify",
		
		//同步跳转
		'return_url' => "http://cakephp.com/api/alipayCallback",

		//编码格式
		'charset' => "UTF-8",

		//签名方式
		'sign_type'=>"RSA2",

		//支付宝网关(这里记得沙箱网址为https://openapi.alipaydev.com)
    	//'gatewayUrl' => "https://openapi.alipay.com/gateway.do",
		'gatewayUrl' => "https://openapi.alipaydev.com/gateway.do",

		//支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。
		'alipay_public_key' => "",

        //日志路径
        'log_path' => "",
);

到这里我们就可以参考sdk代码编写支付代码。

代码

    //去支付逻辑,点击支付按钮调用该接口
    public function pay()
    {
        $request = $_SERVER['REQUEST_METHOD'] == "POST" ? $_POST : $_GET;
        //过滤参数
        $data = $this->publicFunction->filterParams($request);
        //模拟订单
        $orderId = "PAY".time().rand(1000000,10000000); //模拟订单编号
        $subject = "金币"; //模拟商品名称
        $amount = rand(0.1,100); //模拟金额
        $body = "买了不会发货"; //模拟描述
        //支付方式,默认alipay
        switch ($data['pay_type']) {
            case "wechet":
                break;
            case "alipay":
            default :
                //这里使用的是自动提交表单,这里将表单隐藏,避免显示
                echo "<form id='alipayment' action='/alipay/pagepay/pagepay.php' method='post' style='display: none;'>
                <input id='WIDout_trade_no' name='WIDout_trade_no' value=$orderId/>
                <input id='WIDsubject' name='WIDsubject' value=$subject/>
                <input id='WIDtotal_amount' name='WIDtotal_amount' value=$amount />
                <input id='WIDbody' name='WIDbody' value=$body/>
                </form><script>document.getElementById('alipayment').submit();</script>";
                break;
        }
    }

    //支付宝同步回调
    public function alipayCallback()
    {
        $request = $_SERVER['REQUEST_METHOD'] == "POST" ? $_POST : $_GET;
        $data = $this->publicFunction->filterParams($request);
        $config = "";//无用
        require_once("./alipay/config.php");
        require_once './alipay/pagepay/service/AlipayTradeService.php';
        $alipaySevice = new \AlipayTradeService($config);
        //检验参数
        $result = $alipaySevice->check($data);
        if ($result) {
            //这里可以做支付成功的页面跳转
            echo "支付成功"; //test
        } else {
            //这里可以做支付失败的页面跳转
            echo "支付失败"; //test
        }
        die;
    }

    //支付宝异步回调
    public function aliPayNotify()
    {
        $request = $_SERVER['REQUEST_METHOD'] == "POST" ? $_POST : $_GET;
        $data = $this->publicFunction->filterParams($request);
        $config = "";//无用
        //记录请求参数,本次请求的详细信息,方便排查问题
        $this->log('aliPayNotify-params:'.json_encode($data),LOG_INFO);
        require_once("./alipay/config.php");
        require_once './alipay/pagepay/service/AlipayTradeService.php';
        $alipaySevice = new \AlipayTradeService($config);
        $result = $alipaySevice->check($data);
        //验签失败
        if (!$result){
            //验签失败记录日志
            $this->log('aliPayNotify-error:验签失败'.json_encode($data),LOG_ERR);
            echo "fail";die;
        }
        //商户订单号
        $out_trade_no = $data['out_trade_no'];
        //交易总金额
        $total_amount = $data['total_amount'];
        //交易状态
        $trade_status = $data['trade_status'];
        if ($trade_status == "TRADE_FINISHED"){
            //成功记录日志
            $this->log('aliPayNotify-success',LOG_INFO);
            echo "success";die;
        }
        //对订单做判断
        //订单号是否存在数据库中查看
        $order_id = "PAY16443728188675342";//test
        //总交易金额,数据库中查看
        $amount = 100;//test
        if ($total_amount != $amount) {
            //记录失败:订单金额与支付金额不符
            $this->log('aliPayNotify-error:订单金额与支付金额不符'.json_encode($data),LOG_ERR);
            echo "fail";die;
        }
        if (!$order_id){
            //记录失败:订单不存在
            $this->log('aliPayNotify-error:订单不存在'.json_encode($data),LOG_ERR);
            echo  "fail";die;
        }
        //这里我只做了一个简单的模拟支付demo,未对数据库、数据进行操作,后续有需要时会详细补充支付成功后的逻辑代码。
        
        //支付成功逻辑处理代码,对订单以及其他逻辑进行修改
		
        //记录支付宝交易信息到日志记录表中,需要记录支付宝的支付编号,以及此次支付宝传递过来的参数,方便后续排查。
        
		//记录成功日志
        $this->log('aliPayNotify-success',LOG_INFO);
        echo "success";die;
    }
模拟支付宝验证签名流程

控制器代码:

 //验签流程

    //获取签名
    public function getSign($params)
    {
        if (!empty($params)) {
            //验证签名时传递的参数会多两个将哪两个参数去掉,不然验证会失败
            if (isset($params['sign']) || isset($params['sign_type'])) {
                unset($params['sign']);
                unset($params['sign_type']);
            }
            //现将数组进行排序,使用ksort改变数组的顺序,保证同样的数组不会出现其他排列顺序
            ksort($params);
            $signStr = "";
            foreach ($params as $k => $v){
                //$v为空不做加密处理
                if (empty($v)){
                    continue;
                }
                //避免最后多一个&符号
                if ($k == 0){
                    $signStr .= $k.'='.$v;
                }else{
                    $signStr .= '&'.$k.'='.$v;
                }
            }
            //加密签名操作
            $sign = $this->publicFunction->encrypt($signStr); //encrypt为自己封装的加密方法
            $res = [
                'sign' => $sign,
                'sign_type' => "encrypt" //这里返回加密的类型,自定义的名称
            ];
            return $res;
        }
        return false;
    }

    //验证签名
    public function checkSign($params)
    {
        $newSign = $this->getSign($params);
        if ($newSign['sign'] == $params['sign']) {
            return true;
        }
        return false;
    }


    //发送请求
    public function send()
    {
        $data = [
            'out_trade_no' => '213123123123123123',
            'total_amount' => '100.00',
            'time' => time(),
        ];
        $sign = $this->getSign($data);
        $data['sign'] = $sign['sign'];
        $data['sign_type'] = $sign['sign_type'];
        $url = "http://cakephp.com/api/notify";
        //请求对签名进行验证
        $res = $this->publicFunction->curlRequest($url, true, $data);
        var_dump($res);die;//未修改签名参数则验证成功,修改过则验证失败。
    }

    public function notify()
    {
        //参数获取
        $request = $_SERVER['REQUEST_METHOD'] == "POST" ? $_POST : $_GET;
        $data = $this->publicFunction->filterParams($request);//封装的过滤接收参数的方法
        //参数验证
        $res = $this->checkSign($data);
        if ($res){
            echo  "验证成功";die;
        }else{
            echo "验证失败";die;
        }
    }

助手函数

/**
     *
     * 过滤输入非安全字符
     *
     * @param $subject array or string ex: $_GET 需要过滤的数组或字符,可以直接传递$_GET/$_POST
     * @param $substr array(key=>value) ex: array('username'=>12, 'desc'=>120) 数组字段允许的最大长度
     * @param $allowhtml bool ex:true 是否允许html标签
     *
     * @return $subject
     *
     */
    function filterParams($subject, $substr = array(), $allowhtml = true)
    {
        //空字符串
        if (empty($subject) || is_bool($subject) || is_numeric($subject))
            return $subject;

        if (is_array($subject)) {
            foreach ($subject as $key => $val) {
                //数组中存在限制长度的字段
                if (array_key_exists($key, $substr) && is_string($val)) {
                    //截取指定长度
                    $val = mb_substr($val, 0, $substr[$key], 'utf-8');
                }
                //递归执行filterParams方法,将数组全部过滤。
                $subject[$key] = $this->filterParams($val, $substr, $allowhtml);
            }
            return $subject;
        } else {
            //防止xss
            $subject = str_ireplace(";", "", $subject);
            $subject = str_ireplace("&", "&amp;", $subject);
            $subject = str_ireplace("<", "&lt;", $subject);
            $subject = str_ireplace(">", "&gt;", $subject);
            $subject = str_ireplace("'", "", $subject);
            $subject = str_ireplace("--", "", $subject);
		    $subject = str_ireplace("%", "", $subject);
            $subject = str_ireplace("$", "", $subject);
            //防止sql注入
            $subject = str_ireplace("select", "", $subject);
            $subject = str_ireplace("join", "", $subject);
            $subject = str_ireplace("union", "", $subject);
            $subject = str_ireplace("where", "", $subject);
            $subject = str_ireplace("insert", "", $subject);
            $subject = str_ireplace("delete", "", $subject);
            $subject = str_ireplace("update", "", $subject);
            $subject = str_ireplace("like", "", $subject);
            $subject = str_ireplace("drop", "", $subject);
            $subject = str_ireplace("create", "", $subject);
            $subject = str_ireplace("modify", "", $subject);
            $subject = str_ireplace("rename", "", $subject);
            $subject = str_ireplace("alter", "", $subject);
            $subject = str_ireplace("cast", "", $subject);
            //是否允许html标签,不允许去除html标签
            return $allowhtml ? trim($subject) : trim(strip_tags($subject));
        }
    }

/**
     * 发送curl请求
     * @param $url 请求url
     * @param bool $post 请求类型是否为post
     * @param array $params 请求参数
     * @param bool $https 是否为https请求
     * @return bool|string
     */
    function curlRequest($url, $post = true, $params = array(), $https = true)
    {
        //初始化请求会话
        $ch = curl_init($url);
        if ($post) {
            //设置请求方式为post
            curl_setopt($ch, CURLOPT_POST, true);
            //设置请求参数
            curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
        }
        if ($https) {
            //如果是https协议,禁止服务器验证本地证书
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        }
        //发送请求,获取返回参数
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $res = curl_exec($ch);
        //关闭请求
        curl_close($ch);
        return $res;
    }

/**
     * @param $data 加密字段
     * @return string 
     */
    function encrypt($data)
    {
        $salt = "123123asdasdasd";
        $psw = md5($salt . md5($data));
        return $psw;
    }

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在SpringBoot中接入支付宝沙箱支付,您需要完成以下步骤: 1. 注册一个支付宝沙箱账号并登录到开发者平台(https://openhome.alipay.com/platform/appDaily.htm)。 2. 创建一个应用程序并获取应用程序ID和商户私钥。 3. 在SpringBoot应用程序中添加alipay-sdk依赖项。您可以通过Gradle或Maven添加此依赖项。 4. 创建一个支付工具类,并实现沙箱环境的初始化和支付宝支付API的调用。 5. 在SpringBoot应用程序中创建一个控制器,并定义处理支付请求的端点。 6. 在控制器中使用支付工具类处理支付请求,并返回支付结果。 下面是一个示例支付工具类: ```java import com.alipay.api.AlipayClient; import com.alipay.api.AlipayConstants; import com.alipay.api.DefaultAlipayClient; import com.alipay.api.request.AlipayTradePagePayRequest; import com.alipay.api.response.AlipayTradePagePayResponse; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component public class AlipayUtil { @Value("${alipay.app-id}") private String appId; @Value("${alipay.private-key}") private String privateKey; @Value("${alipay.public-key}") private String publicKey; @Value("${alipay.gateway-url}") private String gatewayUrl; @Value("${alipay.notify-url}") private String notifyUrl; public String pay(String outTradeNo, String subject, String totalAmount) throws Exception { AlipayClient alipayClient = new DefaultAlipayClient(gatewayUrl, appId, privateKey, AlipayConstants.FORMAT_JSON, AlipayConstants.CHARSET_UTF8, publicKey, AlipayConstants.SIGN_TYPE_RSA2); AlipayTradePagePayRequest request = new AlipayTradePagePayRequest(); request.setReturnUrl(notifyUrl); request.setNotifyUrl(notifyUrl); request.setBizContent("{\"out_trade_no\":\"" + outTradeNo + "\"," + "\"total_amount\":\"" + totalAmount + "\"," + "\"subject\":\"" + subject + "\"," + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}"); AlipayTradePagePayResponse response = alipayClient.pageExecute(request); return response.getBody(); } } ``` 在这个示例中,我们使用AlipayClient类创建了一个Alipay客户端,并使用AlipayTradePagePayRequest类设置了支付请求参数。我们还使用AlipayTradePagePayResponse类处理Alipay的支付响应。 下面是一个示例控制器: ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; @RestController public class PaymentController { @Autowired private AlipayUtil alipayUtil; @PostMapping("/pay") public String pay(@RequestBody Payment payment) throws Exception { return alipayUtil.pay(payment.getOutTradeNo(), payment.getSubject(), payment.getTotalAmount()); } } ``` 在这个示例中,我们使用@Autowired注释注入了AlipayUtil类,并在/pay端点上定义了处理支付请求的方法。 现在您可以使用Postman或其他HTTP客户端向/pay端点发送JSON请求,以进行支付。以下是一个示例请求: ``` POST /pay HTTP/1.1 Host: localhost:8080 Content-Type: application/json Cache-Control: no-cache { "outTradeNo": "123456789", "subject": "Test Payment", "totalAmount": "100.00" } ``` 在这个示例中,我们向/pay端点发送一个包含outTradeNo,subject和totalAmount的JSON请求。在支付工具类中,我们使用这些参数调用了支付宝API,并返回了支付响应。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值