前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Hyperf + uni-app 使用 EasyWechat 实现微信小程序登录和支付

Hyperf + uni-app 使用 EasyWechat 实现微信小程序登录和支付

作者头像
hedeqiang
发布2019-12-18 11:32:22
4.4K2
发布2019-12-18 11:32:22
举报
文章被收录于专栏:LaravelCodeLaravelCode

安装 EasyWechat

代码语言:javascript
复制
composer require overtrue/wechat:~4.0 -vvv

修改 SWOOLE_HOOK_FLAGS 编辑 bin/hyperf.php 文件

代码语言:javascript
复制
<?php

! defined('SWOOLE_HOOK_FLAGS') && define('SWOOLE_HOOK_FLAGS', SWOOLE_HOOK_ALL | SWOOLE_HOOK_CURL);

配置

创建配置文件 config/autoload/wechat.php

代码语言:javascript
复制
touch config/autoload/wechat.php
代码语言:javascript
复制
<?php
declare(strict_types=1);

return [
    /*
     * 小程序
     */
     'mini_program' => [
         'default' => [
             'app_id'  => env('WECHAT_MINI_PROGRAM_APPID', ''),
             'secret'  => env('WECHAT_MINI_PROGRAM_SECRET', ''),
             'token'   => env('WECHAT_MINI_PROGRAM_TOKEN', ''),
             'aes_key' => env('WECHAT_MINI_PROGRAM_AES_KEY', ''),
         ],
     ],

    /*
     * 微信支付
     */
     'payment' => [
         'default' => [
             'sandbox'            => env('WECHAT_PAYMENT_SANDBOX', false),
             'app_id'             => env('WECHAT_PAYMENT_APPID', ''),
             'mch_id'             => env('WECHAT_PAYMENT_MCH_ID', 'your-mch-id'),
             'key'                => env('WECHAT_PAYMENT_KEY', 'key-for-signature'),
             'cert_path'          => env('WECHAT_PAYMENT_CERT_PATH', 'path/to/cert/apiclient_cert.pem'),    // XXX: 绝对路径!!!!
             'key_path'           => env('WECHAT_PAYMENT_KEY_PATH', 'path/to/cert/apiclient_key.pem'),      // XXX: 绝对路径!!!!
             'notify_url'         =>  env('WECHAT_PAYMENT_NOTIFY_URL', ''),                             // 默认支付结果通知地址
         ],
         // ...
     ],
];

编辑 .env 文件

代码语言:javascript
复制
# EasyWechat 小程序账号
WECHAT_MINI_PROGRAM_APPID=wx46f4f2***
WECHAT_MINI_PROGRAM_SECRET=28ddcd98d139a53*****
WECHAT_MINI_PROGRAM_TOKEN=
WECHAT_MINI_PROGRAM_AES_KEY=

# 支付
WECHAT_PAYMENT_SANDBOX=false
WECHAT_PAYMENT_APPID=wx46f4f2***
WECHAT_PAYMENT_MCH_ID=1517****
WECHAT_PAYMENT_KEY=Mm4vhqTUQaskidBr*****
WECHAT_PAYMENT_CERT_PATH=
WECHAT_PAYMENT_KEY_PATH=
WECHAT_PAYMENT_NOTIFY_URL=http://yourdomain/payments/notify

小程序登录

代码语言:javascript
复制
mkdir -p app/Kernel/Oauth
touch app/Kernel/Oauth/WeChatFactory.php

文件内容如下:

代码语言:javascript
复制
<?php

declare(strict_types=1);

namespace App\Kernel\Oauth;

use EasyWeChat\Factory;
use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use Hyperf\Contract\ConfigInterface;
use Hyperf\Guzzle\CoroutineHandler;
use Hyperf\Guzzle\HandlerStackFactory;
use Overtrue\Socialite\Providers\AbstractProvider;
use Psr\Container\ContainerInterface;

class WeChatFactory
{
    /**
     * @var ContainerInterface
     */
    protected $container;

    private $config;

    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
        $this->config = $container->get(ConfigInterface::class)->get('wechat.mini_program.default');

        // 设置 OAuth 授权的 Guzzle 配置
        AbstractProvider::setGuzzleOptions([
            'http_errors' => false,
            'handler' => HandlerStack::create(new CoroutineHandler()),
        ]);
    }

    /**
     * @return \EasyWeChat\MiniProgram\Application
     */
    public function create()
    {
        $app = Factory::miniProgram($this->config);

        // 设置 HttpClient,当前设置没有实际效果,在数据请求时会被 guzzle_handler 覆盖,但不保证 EasyWeChat 后面会修改这里。
        $config = $app['config']->get('http', []);
        $config['handler'] = $this->container->get(HandlerStackFactory::class)->create();
        $app->rebind('http_client', new Client($config));

        // 重写 Handler
        $app['guzzle_handler'] = $this->container->get(HandlerStackFactory::class)->create();

        return $app;
    }

}

新建登录控制器

代码语言:javascript
复制
php bin/hyperf.php gen:controller AuthController

大致内容如下:

代码语言:javascript
复制
<?php

declare(strict_types=1);

namespace App\Controller;

use App\Kernel\Oauth\WeChatFactory;

use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Annotation\AutoController;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Contract\ResponseInterface;

/**
 * @AutoController()
 * Class AuthController
 * @package App\Controller
 */
class AuthController
{
    /**
     * @Inject()
     * @var WeChatFactory
     */
    protected $factory;

    public function login(RequestInterface $request,ResponseInterface $response)
    {
        $code = $request->input('code');
        $encryptedData = $request->input('encrypted_data');
        $iv = $request->input('iv');

        $app = $this->factory->create();
        $session = $app->auth->session($code);
        $userInfo = $app->encryptor->decryptData($session['session_key'], $iv, $encryptedData);
        var_dump($userInfo);
        return $userInfo;
    }
}

前端 uni-app 登录

代码语言:javascript
复制
<template>
    <view>
        <button open-type="getUserInfo" @getuserinfo="login" withCredentials="true">注册</button>
    </view>
</template>
<script>
    export default {
        data() {},
        onLoad() {},
        methods: {
            async login(res) {
                var encryptedData = res.detail.encryptedData
                var iv = res.detail.iv;

                var [, res] = await uni.login({
                    provider: 'weixin'
                });

                var code = res.code;

                uni.request({
                    url: 'http://127.0.0.1:9501/auth/login',
                    method: 'POST',
                    data: {
                        code: code,
                        encrypted_data: encryptedData,
                        iv: iv
                    },
                    success: (res) => {
                        console.log(res.data);
                    }
                });
            },
        },
    }
</script>
file
file

小程序支付

新建一个 app\Kernel\Payment\WeChatFactory.php 文件

代码语言:javascript
复制
mkdir -p app/Kernel/Payment
touch app/Kernel/Payment/WeChatFactory.php
代码语言:javascript
复制
<?php

declare(strict_types=1);

namespace App\Kernel\Payment;

use EasyWeChat\Factory;
use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use Hyperf\Contract\ConfigInterface;
use Hyperf\Guzzle\CoroutineHandler;
use Hyperf\Guzzle\HandlerStackFactory;
use Overtrue\Socialite\Providers\AbstractProvider;
use Psr\Container\ContainerInterface;

class WeChatFactory
{
    /**
     * @var ContainerInterface
     */
    protected $container;

    protected $paymentConfig;

    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
        $this->paymentConfig = $container->get(ConfigInterface::class)->get('wechat.payment.default');

        // 设置 OAuth 授权的 Guzzle 配置
        AbstractProvider::setGuzzleOptions([
            'http_errors' => false,
            'handler' => HandlerStack::create(new CoroutineHandler()),
        ]);
    }

    /**
     * @return \EasyWeChat\Payment\Application
     */
    public function payment()
    {
        $app = Factory::payment($this->paymentConfig);

        // 设置 HttpClient,当前设置没有实际效果,在数据请求时会被 guzzle_handler 覆盖,但不保证 EasyWeChat 后面会修改这里。
        $config = $app['config']->get('http', []);
        $config['handler'] = $this->container->get(HandlerStackFactory::class)->create();
        $app->rebind('http_client', new Client($config));

        // 重写 Handler
        $app['guzzle_handler'] = $this->container->get(HandlerStackFactory::class)->create();

        return $app;
    }
}

新建支付控制器

代码语言:javascript
复制
php bin/hyperf.php gen:controller PaymentsController

代码如下:

代码语言:javascript
复制
<?php

declare(strict_types=1);

namespace App\Controller;

use App\Kernel\Payment\WeChatFactory;
use EasyWeChat\Kernel\Exceptions\Exception;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Annotation\AutoController;
use Hyperf\HttpServer\Annotation\Middleware;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Contract\ResponseInterface;
use Hyperf\Logger\LoggerFactory;
use Symfony\Component\HttpFoundation\Request;
use function EasyWeChat\Kernel\Support\generate_sign;

/**
 * @AutoController()
 * Class PaymentsController
 * @package App\Controller
 */
class PaymentsController extends AbstractController
{

    /**
     * @Inject()
     * @var WeChatFactory
     */
    protected $factory;

    /**
     * @var \Psr\Log\LoggerInterface
     */
    protected $logger;

    protected $rechargeDao;

    public function __construct(LoggerFactory $loggerFactory)
    {
        // 第一个参数对应日志的 name, 第二个参数对应 config/autoload/logger.php 内的 key
        $this->logger = $loggerFactory->get('log', 'default');
    }

    public function index(RequestInterface $request, ResponseInterface $response)
    {
        $this->logger->info("支付开始");

        $app = $this->factory->payment();

        $result = $app->order->unify([
            'body' => 'QQ 会员充值',
            'out_trade_no' => time(),
            'total_fee' => 10,
            //'spbill_create_ip' => '123.12.12.123', // 可选,如不传该参数,SDK 将会自动获取相应 IP 地址
            'notify_url' => config('wechat.payment.default.notify_url'), // 支付结果通知网址,如果不设置则会使用配置里的默认地址
            'trade_type' => 'JSAPI', // 请对应换成你的支付方式对应的值类型
            'openid' => 'ogPdd5bAEOp3tZL1nxavbx7'
        ]);

        if ($result['return_code']  === 'SUCCESS' && $result['return_msg'] === 'OK')
        {
            // 二次验签
            $params = [
                'appId'     => config('wechat.payment.default.app_id'),
                'timeStamp' => time(),
                'nonceStr'  => $result['nonce_str'],
                'package'   => 'prepay_id=' . $result['prepay_id'],
                'signType'  => 'MD5',
            ];

            // config('wechat.payment.default.key')为商户的key
            $params['paySign'] = generate_sign($params, config('wechat.payment.default.key'));
            return $params;
        }
        else{
            //
        }
    }

    public function notify(RequestInterface $request, ResponseInterface $response)
    {
        $this->logger->info("收到回调");

        $app = $this->factory->payment();
        $get = $this->request->getQueryParams();
        $post = $this->request->getParsedBody();
        $cookie = $this->request->getCookieParams();
        $files = $this->request->getUploadedFiles();
        $server = $this->request->getServerParams();
        $xml = $this->request->getBody()->getContents();

        $app['request'] = new Request($get,$post,[],$cookie,$files,$server,$xml);

        $app->handlePaidNotify(function ($message, $fail) {
            $this->logger->error($message['out_trade_no']);
            $this->logger->info($message['return_code']);
            $this->logger->info('回调数据'.json_encode($message));

            if ($message['return_code'] === 'SUCCESS') { // return_code 表示通信状态,不代表支付状态
                // 用户是否支付成功

            }
            // 用户支付失败
            return false;
        });
    }
}

小程序掉起支付代码

代码语言:javascript
复制
<template>
    <view>
        <button @tap="payment">服务订单支付</button>
    </view>
</template>
<script>
    export default {
        data() {},
        onLoad() {},
        methods: {
            async payment() {
                const token = uni.getStorageSync('token');
                uni.getProvider({
                    service: 'payment',
                    success: function(res) {
                        var provider = res.provider[0];
                        uni.request({
                            url: 'http:127.0.0.1:9501/payments/index',
                            method: 'POST',
                            data: {},
                            success: (res) => {
                                uni.requestPayment({
                                    provider: provider,
                                    orderInfo: '腾讯充值中心-QQ会员充值',
                                    timeStamp: res.data.timeStamp.toString(),
                                    nonceStr: res.data.nonceStr,
                                    package: res.data.package,
                                    signType: res.data.signType,
                                    paySign: res.data.paySign,
                                    _deguh: 1,
                                    success(res) {
                                        console.log(res);
                                    },
                                    fail(res) {
                                        console.log(res);
                                    }
                                })
                            }
                        });
                    }
                })
            },
        },
    }
</script>
file
file

至于微信回调地址就得需要生产环境来测试了,沙箱环境我没有测试过,也懒的搞。这里截张生产环境下的回调 Log 信息

file
file
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 安装 EasyWechat
    • 配置
      • 小程序登录
        • 小程序支付
        相关产品与服务
        云开发 CloudBase
        云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为200万+企业和开发者提供高可用、自动弹性扩缩的后端云服务,可用于云端一体化开发多种端应用(小程序、公众号、Web 应用等),避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档