php-基于laravel框架实现微信公众号扫码关注登录

一、依赖包 

1. 关于实现思路流程:可参考以下大佬文章:

laravel结合esaywechat组件实现微信授权登录

Laravel框架 微信授权登陆 代码封装

Laravel——微信授权登陆

1.1 php依赖包网站上输入overtrue/wechat

1.2 进入文档官网

1.3 本文是基于php8.0.2版本的,laravel框架8.5版本,至于为何使用8.0.2版本,是由于在实现支付宝支付功能时,低版本php均会出现composer安装依赖问题,easywechat本文安装的是5.x版本。安装easywechat依赖:(在自己项目目录下运行即可)

composer require overtrue/wechat:~5.0 -vvv

1.4 创建配置文件

php artisan vendor:publish --provider="Overtrue\\LaravelWeChat\\ServiceProvider"

二、配置项目config

2.1 在config中创建easywechat.php(名字可自己定义):

<?php

return [
    'easyWechat' => [
        /**
         * 账号基本信息,请从微信公众平台/开放平台获取
         */
        'app_id' => '',         // AppID
        'secret' => '',     // AppSecret
        'token' => '',          // Token
        'aes_key' => '',  // EncodingAESKey,兼容与安全模式下请一定要填写!!!

        /**
         * 指定 API 调用返回结果的类型:array(default)/collection/object/raw/自定义类名
         * 使用自定义类名时,构造函数将会接收一个 `EasyWeChat\Kernel\Http\Response` 实例
         */
        'response_type' => 'array',
    ],

    /**
     * 日志配置
     *
     * level: 日志级别, 可选为:
     *         debug/info/notice/warning/error/critical/alert/emergency
     * path:日志文件位置(绝对路径!!!),要求可写权限
     */
    'log' => [
    'default' => 'dev', // 默认使用的 channel,生产环境可以改为下面的 prod
    'channels' => [
        // 测试环境
        'dev' => [
            'driver' => 'single',
            'path' => storage_path('logs/easywechat.log'),
            'level' => 'debug',
        ],
        // 生产环境
        'prod' => [
            'driver' => 'daily',
            'path' => storage_path('logs/easywechat.log'),
            'level' => 'info',
        ],
    ],
],

    /**
     * 接口请求相关配置,超时时间等,具体可用参数请参考:
     * http://docs.guzzlephp.org/en/stable/request-config.html
     *
     * - retries: 重试次数,默认 1,指定当 http 请求失败时重试的次数。
     * - retry_delay: 重试延迟间隔(单位:ms),默认 500
     * - log_template: 指定 HTTP 日志模板,请参考:https://github.com/guzzle/guzzle/blob/master/src/MessageFormatter.php
     */
    'http' => [
    'max_retries' => 1,
    'retry_delay' => 500,
    'timeout' => 5.0,
    // 'base_uri' => 'https://api.weixin.qq.com/', // 如果你在国外想要覆盖默认的 url 的时候才使用,根据不同的模块配置不同的 uri
],

    /**
     * OAuth 配置
     *
     * scopes:公众平台(snsapi_userinfo / snsapi_base),开放平台:snsapi_login
     * callback:OAuth授权完成后的回调页地址
     */
    'oauth' => [
    'scopes' => ['snsapi_userinfo'],
    'callback' => '/examples/oauth_callback.php',
],
];

2.2 关于微信公众号配置信息数据,刚开始可以用官方文档的接口测试号,直接申请即可,用于初步调试方便,后面调试通了,再用实际微信公众号的配置信息数据(需要申请),如何申请,直接百度即可。
接口测试号申请:

微信官方文档-公众号

测试号管理:


注意点:在提交以上的【接口配置信息】时,填入的URL,需要返回echostr,才能提交配置信息成功,因为微信会向该接口发送请求,成功访问并且收到echostr返回,微信方才能确定该接口成功,3.1处有说明。微信官方文档里也写有:

三、微信公众号服务器验证

3.1 配置好config,以及测试号管理之后,按照所填入的url,创建该接口:
 

/**
     * 微信公众号服务器验证
     */
    public function notifyEasyWeChat(Request $request)
    {
        $data = $request->all();
        $boolean = self::checkSignature($data);
        Log::info('easywechat', $data);
        Log::info('checkSignature', [$boolean]);
        return $data['echostr'];
    }

/**
     * 验证
     */
    function checkSignature($data)
    {
        $signature = $data["signature"];
        $timestamp = $data["timestamp"];
        $nonce = $data["nonce"];

        $token = config('xxx.xxx.token');//config里自己定义的token,
        $tmpArr = array($token, $timestamp, $nonce);
        sort($tmpArr, SORT_STRING);
        $tmpStr = implode($tmpArr);
        $tmpStr = sha1($tmpStr);

        if ($tmpStr == $signature) {
            return true;
        } else {
            return false;
        }
    }

此处该接口必须定义为get请求,然后返回微信请求的echostr,方能验证接口成功,提交成功2.2处的接口配置信息。可以将其easywechat通过log日志打印出来,如下:

easywechat 
 {
 "signature":"f56fcdd5053370b7a3803777856a08e87dade380",
 "echostr":"8190732441967026149",
 "timestamp":"1704330081",
 "nonce":"784151826"
 } 

[2024-01-04 09:30:32] production.INFO: checkSignature [true] 

四、微信公众号配置信息

4.1 开通后,然后生成的微信公众号配置信息如下:

4.2 上面的2、3、4、5、6、7都是必须的,测试阶段的话,上面的7,可以用明文与密文模式,方便调试,上面的3,必须把自己的服务器的ip填入,不然后续获取access_token,会报错。其他的直接按照要求生成,填入config即可,上面的6对应config的aes_key,上面的2对应的是secret。本人做的时候,都是后知后觉的,走了不少弯路。

五、生成微信二维码

5.1 书写生成微信登录二维码接口:(完成四之后)

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\BaseController;
use App\Http\Response\ApiResponse;
use EasyWeChat\Factory;
use Illuminate\Support\Facades\Cache;

class WeChatController extends BaseController
{
    /**
     * 生成微信登录二维码
     */
    public function qrcodeCreate()
    {
        $config = config('easywechat.easyWechat');
        $app = Factory::officialAccount($config);
        $uuid = date('YmdHis') . rand(0000, 9999);
        $scene_value = 'login-' . $uuid;//此处通过二维码带参数一起带过去,可自己定义
        Cache::put($uuid, 1, 5 * 3600);//此处缓存,可去掉,本人自己的代码逻辑
        $result = $app->qrcode->temporary($scene_value, 5 * 3600);
        $url = $app->qrcode->url($result['ticket']);
        $data = [
            'qrcpde_url' => $url,
            'uuid' => $uuid,
        ];
        return ApiResponse::successData($data);
    }


}

上述代码,使用的是easywechat第三方包依赖实现的,可以在easywechat文档中详见:

接口返回数据:

六、接收微信扫码点击关注公众号之后响应数据(解密)

6.1 定义路由,请求为post,url是第三点验证路由一样,差别在于一个get请求,一个post请求。

        /**
         * 微信公众号
         */
        //微信公众号服务器验证
        $api->get('wechat/easyNotify', [NotifyController::class, 'notifyEasyWechat']);

        //微信公众号扫码登录回调
        $api->post('wechat/easyNotify', [NotifyController::class, 'notifyEWXML']);

6.2 解密用得是openssl,由于微信官方文档提供过于复杂,以及在php7.2之后,一些函数已经是弃用了,也可以说,对于php8.0.2来说,官方提供的解密源代码已经过期了,以下是我参考:微信公众号之安全模式下消息加解密
本人非常感谢这位老哥的文档,解密中的OPENSSL_ZERO_PADDING解决了我一天半都解决不了的bug,在于解密未关注与关注的密文中,关注的密文解不了的问题。以下是本人的代码:
 

 /**
     * 微信公众号扫码登录回调
     */
    public function notifyEWXML()
    {
        // 获取微信服务器推送的数据
        $postData = file_get_contents("php://input");

        //解密与解析xml
        $data = self::xmlToArray($postData);

        //业务操作
        if ($data['Event'] === 'subscribe' || $data['Event'] === 'SCAN') {
            $open_id = $data['FromUserName'];
            $uuid = explode('-', $data['EventKey']);
            $cache_uuid = 'login-' . $uuid[1];
            Cache::put($cache_uuid, $open_id, 5 * 60);
            $user = User::where('open_id', $open_id)->first();
            if (empty($user)) {
                $new_user = new User();
                $new_user->open_id = $open_id;
                $new_user->nickname = '微信用户';
                $new_user->save();
            }

            //响应数据
            event(new WeChatSubscribeEvent($open_id));//此处,是后续的功能,回复用户:登录成功
        }
        echo '';
    }

/**
     * 使用 simplexml_load_string 解析 XML 数据
     * @param $postData --微信公众号响应的xml数据
     */
    public static function xmlToArray($postData)
    {
        //将xml进行解析为数组格式
        $orginArray = json_decode(json_encode(simplexml_load_string($postData, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        Log::info('源数据:', $orginArray);

        //获取微信公众号提供的消息加解密密钥
        $encodingAESKey = config('easywechat.easyWechat.aes_key');
        //由于微信公众号提供的43位,需要加一位,为4的倍数,微信方要求的
        $encodingAESKey = base64_decode($encodingAESKey . '=');

        //openssl_decrypt进行解密
        $decryptedData = self::decryptWeChatResponse($orginArray['Encrypt'], $encodingAESKey);
        //去掉额外的没用的字符串
        $pattern = '/<xml>(.*?)<\/xml>/s';
        $postArray = '';
        if (preg_match($pattern, $decryptedData, $matches)) {
            $xmlData = $matches[0];
            //xml转数组
            $postArray = json_decode(json_encode(simplexml_load_string($xmlData, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        }
        Log::info('解析xml后数据', [$postArray]);
        return $postArray;
    }

/**
     * 微信公众号解密
     * @param $encryptedData --加密的数据
     * @param $encodingAESKey --微信公众号上的消息加解密密钥
     */
    public static function decryptWeChatResponse($encryptedData, $encodingAESKey)
    {
        // 将 Base64 编码的加密数据解码
        $decodedData = base64_decode($encryptedData);

        // 获取 AES 密钥的前 32 个字符作为实际密钥
        $encodingAESKey = substr($encodingAESKey, 0, 32);

        // 使用 openssl_decrypt 进行解密
        $decryptedData = openssl_decrypt(
            $decodedData,                   // 待解密的数据
            'aes-256-cbc',                  // 解密算法
            $encodingAESKey,                // 解密密钥
            OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING,               // 输出原始数据,不进行 base64 编码,此处很关键
            substr($encodingAESKey, 0, 16)  // 初始化向量(IV),长度为 16 字节
        );
        Log::info('解密后数据', [$decryptedData]);
        // 返回解密后的数据
        return $decryptedData;
    }

6.3 解密关注响应的密文的关键:

6.4 解密后的格式如下:

EventKey中,正是携带的参数

6.5 如果在实现中碰到的问题,需要往composer.json添加的,直接添加即可,其他问题,需要自己解决了。本文,是本人实现后所记录的,其中很多细节无法复现了,也碰到了不少的问题。不过本人都能解决,各位大佬肯定也能。

七、响应用户消息

7.1 功能实现效果如下:

7.2 创建事件处理程序:

php artisan make:event WeChatSubscribeEvent

7.3 在生成的 WeChatSubscribeEvent 类中定义处理逻辑,例如:


namespace App\Events;

use Illuminate\Foundation\Events\Dispatchable;

class WeChatSubscribeEvent
{
    use Dispatchable;

    public $openid;

    public function __construct($openid)
    {
        $this->openid = $openid;
    }
}

7.4 注册事件监听器:

EventServiceProvider 中注册事件监听器:

// app/Providers/EventServiceProvider.php

protected $listen = [
    'App\Events\WeChatSubscribeEvent' => [
        'App\Listeners\WeChatSubscribeListener',
    ],
];

7.5 创建事件监听器:

创建一个事件监听器,用于处理关注事件:

php artisan make:listener WeChatSubscribeListener

在生成的 WeChatSubscribeListener 类中定义响应逻辑,例如:

// app/Listeners/WeChatSubscribeListener.php

namespace App\Listeners;

use App\Events\WeChatSubscribeEvent;

class WeChatSubscribeListener
{
    public function handle(WeChatSubscribeEvent $event)
    {
        $openid = $event->openid;

        // 在这里编写响应逻辑,例如发送“登录成功”的消息
        // 使用 EasyWeChat 的 OfficialAccount 实例来发送消息
        // 在这里编写响应逻辑,例如发送“登录成功”的消息
        $openid = $event->openid;
        $config = config('xxx.xxx');
        $app = Factory::officialAccount($config);
        $app->customer_service->message('登录成功!')->to($openid)->send();
    }
}

7.6 触发事件:

// 在你的控制器或其他地方触发关注事件
event(new \App\Events\WeChatSubscribeEvent($openid));

放到微信响应的代码中即可。

八、总结

        这是本人第一次写文章,比较生疏,后续还会有更新。本人刚从事php方向一年,之前用的框架是tp6,第一次接触laravel框架,又爱又恨,恨其依赖问题过于繁琐,麻烦,难以解决,不过,这也是没办法避免的。希望大家点点关注,给予小白一些写作动力,能关注一下php小白的平凡之旅!非常感谢,大家有问题可以私信,看到会积极响应的。

  • 20
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Flask是一种轻量级的Python Web框架,能够方便地构建网页应用程序。要实现微信公众号扫码关注登录网页功能,可以使用Flask结合微信开发接口进行实现。 首先,需要在微信公众平台上注册并创建一个公众号,并获取到相关的开发者ID和密钥。 接下来,搭建Flask应用程序,先安装Flask库,并导入相关的依赖库,如wechatpy和requests库等。 然后,创建一个Flask路由,用于接收微信服务器的验证请求和菜单跳转等请求。根据微信开发文档,编写逻辑代码,进行验证和处理微信服务器的各种请求。 在处理菜单跳转请求时,可以通过微信JS-SDK提供的扫一扫功能,生成一个特定的二维码,用于用户关注公众号。二维码中包含一个唯一的标识码,用于识别用户和公众号之间的关系。 当用户扫描二维码关注公众号后,微信服务器会向事先设置的回调URL发送消息通知。在Flask应用程序中,可以通过编写对应的路由来处理该通知,获取到用户的唯一标识码。然后,可以将该标识码与用户相关的信息存储到数据库中,以便后续使用。 最后,通过编写相关的路由和模板,实现用户登录网页功能。当用户点击网页中的登录按钮时,可以跳转到微信授权登录页面。用户授权后,微信会将用户的唯一标识码和相关信息返回到事先设置的回调URL。在Flask应用程序中,处理该回调URL的路由中,可以获取到用户的标识码,从数据库中获取用户信息,并进行登录操作。 综上所述,通过使用Flask框架结合微信开发接口,可以实现微信公众号扫码关注登录网页功能。这样的实现方式能够方便地与微信公众号进行交互,并提供给用户一个方便、安全的登录方式。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值