easywechat laravel 公众号 微信支付
首先、申请微信商户平台,申请微信支付,公众号关联微信商户平台
公众号可以通过jsapi来实现公众号微信支付
一、业务页面
@extends('m.order') @section('content') <style type="text/css"> input, textarea { border: 0; -webkit-appearance: none; } </style> <section class="container"> <div class="pay_main"> <div class="ay_ma1"><span>付款金额</span><em><i>¥</i>{{$total_price}}</em></div><!--ay_ma1--> <div class="ay_ma2">订单编号:{{$order_no}}</div><!--ay_ma2--> <div class="ay_ma2">付款方式</div><!--ay_ma2--> <div class="ay_ma3"><span>微信支付</span><label></label></div> {{--<div class="ay_ma3"><span>微信支付</span><label><input name="" type="radio" value="" checked></label></div>--}} <div class="ay_ma4"> <ul> <button type="button" onclick="wxPay()" id="pay_button">确认付款</button> </ul> </div><!--ay_ma4--> </div><!--pay_main--> <input type="hidden" id="order_no" value="{{$order_no}}"> <input type="hidden" id="code" value=""> </section> @endsection @section('js') <script type="text/javascript" src="/static/new/m/js/jweixin-1.4.0.js"></script> <script type="text/javascript" src="/static/new/m/js/pay.js"></script> @endsection
二、前端pay.js逻辑
$(function () { var layer; layui.use(['layer'], function () { layer = layui.layer; }); $('#pay_button').hide(); wxConfig(); wx.ready(function(){ $('#pay_button').show(); }); }); function wxConfig() { var order_no = $('#order_no').val(); $.ajax({ type:"GET", url:"/wechat/pay", data:{order_no:order_no}, success:function (config) { // 微信配置 wx.config({ debug: false, appId: config.appId, timestamp: config.timeStamp, nonceStr: config.nonceStr, signature: config.signature, jsApiList: ['chooseWXPay'] }); } }); } function wxPayAuth(orderPayNo) { window.location.href = '/mp/oauth?targetUrl=/pay/request?orderPayNo=' + orderPayNo; } var jsApiConfig; function wxPay() { var order_no = $('#order_no').val(); $.ajax({ type:"GET", url:"/wechat/pay", data:{order_no:order_no}, success:function (config) { jsApiConfig = config;//请求微信成功返回的支付参数 callpay(); } }) } //调用微信JS api 支付 function jsApiCall() { WeixinJSBridge.invoke( 'getBrandWCPayRequest',jsApiConfig, function(res){ //WeixinJSBridge.log(res.err_msg); //alert(res.err_code+res.err_desc+res.err_msg); if(res.err_msg == "get_brand_wcpay_request:ok" ) { layer.msg('支付成功', {time: 1000, end: function () { location.href = '/inquiry/index'; }}); }else{ layer.msg('支付失败,请重试'); } }); } function callpay() { if (typeof WeixinJSBridge == "undefined"){ if( document.addEventListener ){ document.addEventListener('WeixinJSBridgeReady', jsApiCall, false); }else if (document.attachEvent){ document.attachEvent('WeixinJSBridgeReady', jsApiCall); document.attachEvent('onWeixinJSBridgeReady', jsApiCall); } }else{ jsApiCall(); } }
三、服务端处理页面
<?php namespace App\Http\Controllers\M; use App\Library\Common; use App\Library\Y; use App\Models\Member\MemberConnect; use App\Models\Prod\Order; use App\Models\Prod\SaleOrder; use App\Services\Wechat\MenuService; use App\Services\Wechat\MessageService; use App\Services\Wechat\UserService; use Illuminate\Http\Request; use App\Http\Controllers\Controller; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Log; class WeChatController extends Controller { // /** * 处理微信的请求消息 * * @return string */ /* public function serve() { Log::info('request arrived.'); # 注意:Log 为 Laravel 组件,所以它记的日志去 Laravel 日志看,而不是 EasyWeChat 日志 $app = app('wechat.official_account'); $app->server->push(function($message){ return "欢迎关注 一览商城!"; }); return $app->server->serve(); }*/ public function serve(MessageService $messageService) { Log::info('request arrived.'); # 注意:Log 为 Laravel 组件,所以它记的日志去 Laravel 日志看,而不是 EasyWeChat 日志 $app = app('wechat.official_account'); $app->server->push(function($message) use($messageService){ return $messageService->index($message); }); return $app->server->serve(); } /** * 登录时请求验证 * @return mixed */ public function login_oauth(){ Log::info('start', ['login_oauth']); $member_id= isset(auth('member')->user()->id) ?auth('member')->user()->id : 0; //判断是否存在 openid if(!Common::getOpenid($member_id)){ $app = app('wechat.official_account'); return $response = $app->oauth->scopes(['snsapi_userinfo'])->redirect(route('m.login_callback')); } return redirect(route('m.member.index')); } /** * 登录时请求回调 * @return mixed */ public function login_callback(){ Log::info('start', ['login_callback']); $app = app('wechat.official_account'); // 获取 OAuth 授权结果用户信息 $user = $app->oauth->user(); if(!$user){ Log::info('oauth_callback_user_error', ['none user']); } $openid = $user->getId(); $UserService = new UserService(); $user_info =$UserService->getUserInfo($openid); $member_id= isset(auth('member')->user()->id) ?auth('member')->user()->id : 0; //查询openid 有没有绑定 member $memberConnect = MemberConnect::where('openid', '=', $openid)->first(); if(!$memberConnect){ //没保存先保存memberConnect Common::createMemberConnect($user_info, 3); } //绑定openid memberid MemberConnect::where('openid', '=', $openid)->update(['member_id'=>$member_id]); //如果登录,则保存微信用户信息进cache if($member_id > 0){ Log::info('login_callback_cache', [$user_info]); Cache::add("wx_user:".$member_id, $user_info); } return redirect(route('m.member.index')); } /** * 发起授权 * @return mixed */ public function oauth(){ Log::info('start', ['oauth']); $member_id= isset(auth('member')->user()->id) ?auth('member')->user()->id : 0; //已登录状态 if($member_id > 0){ $memberConnect = MemberConnect::where('member_id', '=', $member_id)->first(); //如果会员已绑定,直接跳转会员主页 if($memberConnect) return redirect(route('m.member.index')); //如果会员没绑定,查看openid是否绑定 $openid = Common::getOpenid($member_id); if($openid){ $memberConnect = MemberConnect::where('openid', '=', $openid)->first(); //存在则更新 if($memberConnect){ MemberConnect::where('openid', '=', $openid)->update(['member_id'=>$member_id]); return redirect(route('m.member.index')); } } } $app = app('wechat.official_account'); return $app->oauth->scopes(['snsapi_userinfo'])->redirect(); } /** * 授权回调 * @return mixed */ public function callback(){ Log::info('start', ['oauth_callback']); // 获取 OAuth 授权结果用户信息 $app = app('wechat.official_account'); $user = $app->oauth->user(); if(!$user) Log::info('oauth_callback', ['none user']); $openid = $user->getId(); $UserService = new UserService(); $user_info =$UserService->getUserInfo($openid); //查询openid 有没有绑定 member $memberConnect = MemberConnect::where('openid', '=', $openid)->first(); $member_id = 0; if(!$memberConnect){ //没保存先保存memberConnect Common::createMemberConnect($user_info, 3); }else{ $member_id = $memberConnect->member_id; } if($member_id > 0){ //openid 已经跟会员member绑定,则默认登录 Auth::guard('member')->loginUsingId($member_id); //加入openid缓存 Cache::add("wx_user:".$member_id, $user_info); Log::info('wechat login email', [auth('member')->user()->email]); return redirect(route('m.member.index')); } if($member_id ==0 ){ //openid还没跟会员member绑定,提醒用户去设置绑定 return redirect(route('m.bind_account', array('openid'=>$openid))); } } public function wxMenu(Request $request,MenuService $menuService){ $buttons = [ [ "name" => "我要采购", "sub_button" => [ [ "type" => "view", "name" => "发布采购", "url" => "http://m.bychem.com/inquiry/add" ], [ "type" => "view", "name" => "采购管理", "url" => "http://m.bychem.com/inquiry/lists?type=quote" ], [ "type" => "view", "name" => "采购订单", "url" => "http://m.bychem.com/order/lists?type=pay" ], ], ], [ "name" => "我要销售", "sub_button" => [ [ "type" => "view", "name" => "发布产品", "url" => "http://m.bychem.com/sale/goods_add" ], [ "type" => "view", "name" => "产品管理", "url" => "http://m.bychem.com/sale/goods_list" ], [ "type" => "view", "name" => "询盘管理", "url" => "http://m.bychem.com/sale/lists" ], [ "type" => "view", "name" => "销售订单", "url" => "http://m.bychem.com/sale/order" ], ], ], [ "name" => "会员中心", "sub_button" => [ [ "type" => "view", "name" => "注册/登录", "url" => "http://m.bychem.com/users/sign_in" ], [ "type" => "view", "name" => "会员中心", "url" => "http://m.bychem.com/member/index" ], [ "type" => "click", "name" => "联系客服", "key" => "CONTACT_KEFU" ], ], ], ]; return $menuService->index($request,$buttons); } /** * 公众号微信支付成功回调 * @param Request $request * @return mixed */ public function wechat_notify(Request $request){ Log::info('start', ['wechat mp notify']); $payment = app('wechat.payment'); $response = $payment->handlePaidNotify(function ($message, $fail) { Log::info('wechat mp notify msg', [$message]); if ($message['return_code'] === 'SUCCESS' && $message['result_code'] === 'SUCCESS') { Order::where('id','=', $message['out_trade_no'])->update(['is_pay' => 1,'status' => 2,'trade_no'=>$message['transaction_id'],'pay_method'=>'微信']);//更改订单状态 //更新销售合同支付状态 SaleOrder::where('order_id','=',$message['out_trade_no'])->update(['is_pay'=>1]); //支付后,微信会在此处返回支付状态,就是$message,回调里面打印不出来,可通过写入日志里面查看,支付成功后更改订单状态。当然你也可以进行其他操作。 return true; } else { return $fail('失败'); } }); return $response; } /** * 发起支付 * 组合微信支付需要参数 * @param Request $request * @return mixed */ public function pay(Request $request){ Log::info('start',['wechat paying']); $order_no = $request->get('order_no'); $member_id = isset(auth('member')->user()->id) ?auth('member')->user()->id : 0; //判断是否有权限操作此订单 $order = Order::where('order_no', '=', $order_no)->first(); if($order->user_id != $member_id) return Y::error('没有权限操作!'); $total_price = $order->total_price; $total_price = $total_price * 100;//微信支付以分为单位 $openid = Common::getOpenid($member_id); if(!$openid) return Y::error('没有openid!请重新登录'); Log::info('wechat repay',[$order_no, $member_id,$total_price, $openid]); $payment = app('wechat.payment'); //统一下单 $result = $payment->order->unify([ 'body' => '微信支付', 'out_trade_no' => $order->id, 'total_fee' => $total_price, //'notify_url' => 'http://m.bychem.com/wechat/payments/wechat-notify', //回调地址,用于接收微信支付结果 'notify_url' => route('m.wechat_notify'), //回调地址,用于接收微信支付结果 'trade_type' => 'JSAPI', 'openid' => $openid, ]); Log::info('wechat payment result',[$result]); if ($result['result_code'] == 'SUCCESS' && $result['return_code'] == 'SUCCESS') { $prepayId = $result['prepay_id']; $jssdk = $payment->jssdk; $config = $jssdk->sdkConfig($prepayId); $config['timestamp'] = strval(time()); $config['timeStamp'] = strval(time()); Log::info('wechat config',[$config]); return $config; } else { Log::info('wechat config un_success',[$result]); return $result; } } }
四、csrf排除
<?php namespace App\Http\Middleware; use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware; class VerifyCsrfToken extends Middleware { /** * Indicates whether the XSRF-TOKEN cookie should be set on the response. * * @var bool */ protected $addHttpCookie = true; /** * The URIs that should be excluded from CSRF verification. * * @var array */ protected $except = [ 'wechat_notify', 'ali_notify', 'wechat', 'wechat/*', 'payments/*' ]; }