当前位置:   article > 正文

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

hyperf easywechat

安装 EasyWechat

composer require overtrue/wechat:~4.0 -vvv

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

  1. <?php
  2. ! defined('SWOOLE_HOOK_FLAGS') && define('SWOOLE_HOOK_FLAGS', SWOOLE_HOOK_ALL | SWOOLE_HOOK_CURL);

配置

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

touch config/autoload/wechat.php
  1. <?php
  2. declare(strict_types=1);
  3. return [
  4. /*
  5. * 小程序
  6. */
  7. 'mini_program' => [
  8. 'default' => [
  9. 'app_id' => env('WECHAT_MINI_PROGRAM_APPID', ''),
  10. 'secret' => env('WECHAT_MINI_PROGRAM_SECRET', ''),
  11. 'token' => env('WECHAT_MINI_PROGRAM_TOKEN', ''),
  12. 'aes_key' => env('WECHAT_MINI_PROGRAM_AES_KEY', ''),
  13. ],
  14. ],
  15. /*
  16. * 微信支付
  17. */
  18. 'payment' => [
  19. 'default' => [
  20. 'sandbox' => env('WECHAT_PAYMENT_SANDBOX', false),
  21. 'app_id' => env('WECHAT_PAYMENT_APPID', ''),
  22. 'mch_id' => env('WECHAT_PAYMENT_MCH_ID', 'your-mch-id'),
  23. 'key' => env('WECHAT_PAYMENT_KEY', 'key-for-signature'),
  24. 'cert_path' => env('WECHAT_PAYMENT_CERT_PATH', 'path/to/cert/apiclient_cert.pem'), // XXX: 绝对路径!!!!
  25. 'key_path' => env('WECHAT_PAYMENT_KEY_PATH', 'path/to/cert/apiclient_key.pem'), // XXX: 绝对路径!!!!
  26. 'notify_url' => env('WECHAT_PAYMENT_NOTIFY_URL', ''), // 默认支付结果通知地址
  27. ],
  28. // ...
  29. ],
  30. ];

编辑 .env 文件

  1. # EasyWechat 小程序账号
  2. WECHAT_MINI_PROGRAM_APPID=wx46f4f2***
  3. WECHAT_MINI_PROGRAM_SECRET=28ddcd98d139a53*****
  4. WECHAT_MINI_PROGRAM_TOKEN=
  5. WECHAT_MINI_PROGRAM_AES_KEY=
  6. # 支付
  7. WECHAT_PAYMENT_SANDBOX=false
  8. WECHAT_PAYMENT_APPID=wx46f4f2***
  9. WECHAT_PAYMENT_MCH_ID=1517****
  10. WECHAT_PAYMENT_KEY=Mm4vhqTUQaskidBr*****
  11. WECHAT_PAYMENT_CERT_PATH=
  12. WECHAT_PAYMENT_KEY_PATH=
  13. WECHAT_PAYMENT_NOTIFY_URL=http://yourdomain/payments/notify

小程序登录

  1. mkdir -p app/Kernel/Oauth
  2. touch app/Kernel/Oauth/WeChatFactory.php

文件内容如下:

  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Kernel\Oauth;
  4. use EasyWeChat\Factory;
  5. use GuzzleHttp\Client;
  6. use GuzzleHttp\HandlerStack;
  7. use Hyperf\Contract\ConfigInterface;
  8. use Hyperf\Guzzle\CoroutineHandler;
  9. use Hyperf\Guzzle\HandlerStackFactory;
  10. use Overtrue\Socialite\Providers\AbstractProvider;
  11. use Psr\Container\ContainerInterface;
  12. use Hyperf\Utils\ApplicationContext;
  13. use Psr\SimpleCache\CacheInterface;
  14. class WeChatFactory
  15. {
  16. /**
  17. * @var ContainerInterface
  18. */
  19. protected $container;
  20. private $config;
  21. public function __construct(ContainerInterface $container)
  22. {
  23. $this->container = $container;
  24. $this->config = $container->get(ConfigInterface::class)->get('wechat.mini_program.default');
  25. // 设置 OAuth 授权的 Guzzle 配置
  26. AbstractProvider::setGuzzleOptions([
  27. 'http_errors' => false,
  28. 'handler' => HandlerStack::create(new CoroutineHandler()),
  29. ]);
  30. }
  31. /**
  32. * @return \EasyWeChat\MiniProgram\Application
  33. */
  34. public function create()
  35. {
  36. $app = Factory::miniProgram($this->config);
  37. // 设置 HttpClient,当前设置没有实际效果,在数据请求时会被 guzzle_handler 覆盖,但不保证 EasyWeChat 后面会修改这里。
  38. $config = $app['config']->get('http', []);
  39. $config['handler'] = $this->container->get(HandlerStackFactory::class)->create();
  40. $app->rebind('http_client', new Client($config));
  41. // 重写 Handler
  42. $app['guzzle_handler'] = $this->container->get(HandlerStackFactory::class)->create();
  43. // 重新 Cache
  44. $app['cache'] = ApplicationContext::getContainer()->get(CacheInterface::class);
  45. return $app;
  46. }
  47. }

新建登录控制器

php bin/hyperf.php gen:controller AuthController

大致内容如下:

  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Controller;
  4. use App\Kernel\Oauth\WeChatFactory;
  5. use Hyperf\Di\Annotation\Inject;
  6. use Hyperf\HttpServer\Annotation\AutoController;
  7. use Hyperf\HttpServer\Contract\RequestInterface;
  8. use Hyperf\HttpServer\Contract\ResponseInterface;
  9. /**
  10. * @AutoController()
  11. * Class AuthController
  12. * @package App\Controller
  13. */
  14. class AuthController
  15. {
  16. /**
  17. * @Inject()
  18. * @var WeChatFactory
  19. */
  20. protected $factory;
  21. public function login(RequestInterface $request,ResponseInterface $response)
  22. {
  23. $code = $request->input('code');
  24. $encryptedData = $request->input('encrypted_data');
  25. $iv = $request->input('iv');
  26. $app = $this->factory->create();
  27. $session = $app->auth->session($code);
  28. $userInfo = $app->encryptor->decryptData($session['session_key'], $iv, $encryptedData);
  29. var_dump($userInfo);
  30. return $userInfo;
  31. }
  32. }

前端 uni-app 登录

  1. <template>
  2. <view>
  3. <button open-type="getUserInfo" @getuserinfo="login" withCredentials="true">注册</button>
  4. </view>
  5. </template>
  6. <script>
  7. export default {
  8. data() {},
  9. onLoad() {},
  10. methods: {
  11. async login(res) {
  12. var encryptedData = res.detail.encryptedData
  13. var iv = res.detail.iv;
  14. var [, res] = await uni.login({
  15. provider: 'weixin'
  16. });
  17. var code = res.code;
  18. uni.request({
  19. url: 'http://127.0.0.1:9501/auth/login',
  20. method: 'POST',
  21. data: {
  22. code: code,
  23. encrypted_data: encryptedData,
  24. iv: iv
  25. },
  26. success: (res) => {
  27. console.log(res.data);
  28. }
  29. });
  30. },
  31. },
  32. }
  33. </script>

file

小程序支付

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

  1. mkdir -p app/Kernel/Payment
  2. touch app/Kernel/Payment/WeChatFactory.php
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Kernel\Payment;
  4. use EasyWeChat\Factory;
  5. use GuzzleHttp\Client;
  6. use GuzzleHttp\HandlerStack;
  7. use Hyperf\Contract\ConfigInterface;
  8. use Hyperf\Guzzle\CoroutineHandler;
  9. use Hyperf\Guzzle\HandlerStackFactory;
  10. use Overtrue\Socialite\Providers\AbstractProvider;
  11. use Psr\Container\ContainerInterface;
  12. use Hyperf\Utils\ApplicationContext;
  13. use Psr\SimpleCache\CacheInterface;
  14. class WeChatFactory
  15. {
  16. /**
  17. * @var ContainerInterface
  18. */
  19. protected $container;
  20. protected $paymentConfig;
  21. public function __construct(ContainerInterface $container)
  22. {
  23. $this->container = $container;
  24. $this->paymentConfig = $container->get(ConfigInterface::class)->get('wechat.payment.default');
  25. // 设置 OAuth 授权的 Guzzle 配置
  26. AbstractProvider::setGuzzleOptions([
  27. 'http_errors' => false,
  28. 'handler' => HandlerStack::create(new CoroutineHandler()),
  29. ]);
  30. }
  31. /**
  32. * @return \EasyWeChat\Payment\Application
  33. */
  34. public function payment()
  35. {
  36. $app = Factory::payment($this->paymentConfig);
  37. // 设置 HttpClient,当前设置没有实际效果,在数据请求时会被 guzzle_handler 覆盖,但不保证 EasyWeChat 后面会修改这里。
  38. $config = $app['config']->get('http', []);
  39. $config['handler'] = $this->container->get(HandlerStackFactory::class)->create();
  40. $app->rebind('http_client', new Client($config));
  41. // 重写 Handler
  42. $app['guzzle_handler'] = $this->container->get(HandlerStackFactory::class)->create();
  43. // 重新 Cache
  44. $app['cache'] = ApplicationContext::getContainer()->get(CacheInterface::class);
  45. return $app;
  46. }
  47. }

新建支付控制器

php bin/hyperf.php gen:controller PaymentsController

代码如下:

  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Controller;
  4. use App\Kernel\Payment\WeChatFactory;
  5. use EasyWeChat\Kernel\Exceptions\Exception;
  6. use Hyperf\Di\Annotation\Inject;
  7. use Hyperf\HttpServer\Annotation\AutoController;
  8. use Hyperf\HttpServer\Annotation\Middleware;
  9. use Hyperf\HttpServer\Contract\RequestInterface;
  10. use Hyperf\HttpServer\Contract\ResponseInterface;
  11. use Hyperf\Logger\LoggerFactory;
  12. use Symfony\Component\HttpFoundation\Request;
  13. use function EasyWeChat\Kernel\Support\generate_sign;
  14. /**
  15. * @AutoController()
  16. * Class PaymentsController
  17. * @package App\Controller
  18. */
  19. class PaymentsController extends AbstractController
  20. {
  21. /**
  22. * @Inject()
  23. * @var WeChatFactory
  24. */
  25. protected $factory;
  26. /**
  27. * @var \Psr\Log\LoggerInterface
  28. */
  29. protected $logger;
  30. protected $rechargeDao;
  31. public function __construct(LoggerFactory $loggerFactory)
  32. {
  33. // 第一个参数对应日志的 name, 第二个参数对应 config/autoload/logger.php 内的 key
  34. $this->logger = $loggerFactory->get('log', 'default');
  35. }
  36. public function index(RequestInterface $request, ResponseInterface $response)
  37. {
  38. $this->logger->info("支付开始");
  39. $app = $this->factory->payment();
  40. $result = $app->order->unify([
  41. 'body' => 'QQ 会员充值',
  42. 'out_trade_no' => time(),
  43. 'total_fee' => 10,
  44. //'spbill_create_ip' => '123.12.12.123', // 可选,如不传该参数,SDK 将会自动获取相应 IP 地址
  45. 'notify_url' => config('wechat.payment.default.notify_url'), // 支付结果通知网址,如果不设置则会使用配置里的默认地址
  46. 'trade_type' => 'JSAPI', // 请对应换成你的支付方式对应的值类型
  47. 'openid' => 'ogPdd5bAEOp3tZL1nxavbx7'
  48. ]);
  49. if ($result['return_code'] === 'SUCCESS' && $result['return_msg'] === 'OK')
  50. {
  51. // 二次验签
  52. $params = [
  53. 'appId' => config('wechat.payment.default.app_id'),
  54. 'timeStamp' => time(),
  55. 'nonceStr' => $result['nonce_str'],
  56. 'package' => 'prepay_id=' . $result['prepay_id'],
  57. 'signType' => 'MD5',
  58. ];
  59. // config('wechat.payment.default.key')为商户的key
  60. $params['paySign'] = generate_sign($params, config('wechat.payment.default.key'));
  61. return $params;
  62. }
  63. else{
  64. //
  65. }
  66. }
  67. public function notify(RequestInterface $request, ResponseInterface $response)
  68. {
  69. $this->logger->info("收到回调");
  70. $app = $this->factory->payment();
  71. $get = $this->request->getQueryParams();
  72. $post = $this->request->getParsedBody();
  73. $cookie = $this->request->getCookieParams();
  74. $files = $this->request->getUploadedFiles();
  75. $server = $this->request->getServerParams();
  76. $xml = $this->request->getBody()->getContents();
  77. $app['request'] = new Request($get,$post,[],$cookie,$files,$server,$xml);
  78. $app->handlePaidNotify(function ($message, $fail) {
  79. $this->logger->error($message['out_trade_no']);
  80. $this->logger->info($message['return_code']);
  81. $this->logger->info('回调数据'.json_encode($message));
  82. if ($message['return_code'] === 'SUCCESS') { // return_code 表示通信状态,不代表支付状态
  83. // 用户是否支付成功
  84. }
  85. // 用户支付失败
  86. return false;
  87. });
  88. }
  89. }

小程序掉起支付代码

  1. <template>
  2. <view>
  3. <button @tap="payment">服务订单支付</button>
  4. </view>
  5. </template>
  6. <script>
  7. export default {
  8. data() {},
  9. onLoad() {},
  10. methods: {
  11. async payment() {
  12. const token = uni.getStorageSync('token');
  13. uni.getProvider({
  14. service: 'payment',
  15. success: function(res) {
  16. var provider = res.provider[0];
  17. uni.request({
  18. url: 'http:127.0.0.1:9501/payments/index',
  19. method: 'POST',
  20. data: {},
  21. success: (res) => {
  22. uni.requestPayment({
  23. provider: provider,
  24. orderInfo: '腾讯充值中心-QQ会员充值',
  25. timeStamp: res.data.timeStamp.toString(),
  26. nonceStr: res.data.nonceStr,
  27. package: res.data.package,
  28. signType: res.data.signType,
  29. paySign: res.data.paySign,
  30. _deguh: 1,
  31. success(res) {
  32. console.log(res);
  33. },
  34. fail(res) {
  35. console.log(res);
  36. }
  37. })
  38. }
  39. });
  40. }
  41. })
  42. },
  43. },
  44. }
  45. </script>

file

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

关于极客返利

极客返利 是由我个人开发的一款网课返利、返现平台。包含 极客时间返现、拉勾教育返现、掘金小册返现、GitChat返现。目前仅包含这几个平台。后续如果有需要可以考虑其他平台。 简而言之就是:你买课,我返现。让你花更少的钱,就可以买到课程。

https://geek.laravelcode.cn

https://geek.idaka.ink

版权许可
本作品采用 知识共享署名 4.0 国际许可协议 进行许可。

转载无需与我联系,但须注明出处,注明文章来源 Hyperf + uni-app 使用 EasyWechat 实现微信小程序登录和支付

联系我
编程怪事
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/131954
推荐阅读
相关标签
  

闽ICP备14008679号