admin管理员组

文章数量:1640413

文章目录

      • 前言
      • 1. 开发环境
      • 2. 用窗口显示网页
      • 3. 如何判断网页是否加载完成了?
      • 4. 用窗口显示微信登陆二维码网页
      • 5. 登录过程
      • 6. 获取 code
      • 7. 获取 access_token

前言

最近写一个 pc 软件试试,当然一开始就是用户登录界面咯,跟同学软磨硬泡之下,帮我出了个 ui 图,长这样:

还别说,看上去就是专业,和我本人画半天的好看多了。

那么看到这个 ui 图就知道大概有哪些要实现的功能了。本文就只介绍一下我在实现微信登陆的过程中的经历吧。




完整代码 戳这





1. 开发环境

我们常见的微信登陆都是这个样子的


就一个二维码,用手机扫描即可登录。那么怎么有这个二维码呢?

我们这里用的是在自己的窗口部件中嵌入浏览器,也就是说,在自己的窗口部件中显示网页。二微信登陆的二维码也正是一个网页来的,这个网页就一个二维码。

既然要嵌入浏览器,那么这样一来 Qt 的版本就不能超过 5.6 了,因为 Qt 5.7 以后的版本不支持这个了。

所以综上,这个开发环境就是:

Qt 5.6.3
windows 环境下的


2. 用窗口显示网页

那么我们就先开始来做第一步吧,先显示出指定网页。

首先在 .pro 工程文件中加上

QT += webenginewidgets network

在 .h 文件中加上要用到的头文件:

#include <QUrl>
#include <QWebEngineView>
#include <QWebEngineSettings>
#include <QWebEngineUrlRequestInfo>

然后就是正餐了,要实现加载网页就要用到 QWebEngineView 类,所以我们在 .h 文件中先创建一个全局的响应对象指针:

QWebEngineView *LiveView;		// 创建 web 浏览器显示对象

这样一来准备工作完成,来试试显示 百度(www.baidu) 吧。

在 .cpp 文件中加入以下代码:

	this->LiveView = new QWebEngineView(this);	// 创建对象
    this->LiveView->settings()->setAttribute(QWebEngineSettings::PluginsEnabled, true);	// 设置属性为使能插件
    this->LiveView->setAttribute(Qt::WA_DeleteOnClose);	// 设置属性为关闭时删除
    this->LiveView->load(QUrl("http://www.baidu"));	// 设置加载的网址(http不要忘了哦)
    this->LiveView->resize(500, 500);					// 现实的窗口大小
    this->LiveView->show();								// 显示

运行效果如下:

这样就实现了将网页嵌入到我们自己的窗口之中,是不是很简单?

注意:如果在 .pro 文件加了相应模块后,构建时报出未找到对应的头文件错误的话,请不要慌,点击 构建---->执行qmake 之后再来一次就好啦。



3. 如何判断网页是否加载完成了?

在 QWebEngineView 类中有一个网页加载完成信号

[signal] void QWebEngineView::loadFinished(bool ok);

这样一来我们就可以使用信号和槽来处理加载完成的相关事件。

connect(LiveView, SIGNAL(loadFinished(bool)), this, SLOT(OnLoadFinished()));

关于这个槽函数,我是这样实现的

// 打印一下当前加载完的网址
void OnLoadFinished()
{
    QString currentUrl = LiveView->url().toString();
	qDebug() << "Url = " << currentUrl << endl;
}

就是这样了,具体要在这里实现什么小功能就看各位的脑洞了。



4. 用窗口显示微信登陆二维码网页

那么我们在上一步中实现了将百度网页内嵌到我们的窗口之中,那我们是不是该将微信登陆的二维码网页安排一下了呢?

没错,但是在此之前,我们先看看微信给出的这个二维码网页链接:

https://open.weixin.qq.com/connect/qrconnect?appid=%1&redirect_uri=%2&response_type=code&state=idc_1qloO7huDcIYf9qpjYZ8WkA&scope=snsapi_login#wechat_redirect

这么长咱也看不懂啊,咱现在注意这一段:

appid=%1&redirect_uri=%2

聪明的小伙伴应该已经想到了,没错,这个%1,%2两个地方要填入的内容就是该二维码网页的核心。那么这个 appid 和我们后面要用的 appsecret 是需要我们去向微信申请的。申请过程中要提交我们所要实现的应用名称等信息,经过审核之后就会拿到这两个内容啦。

我这里虽然后,但实在是不方便公开给大家测试,所以请各位小伙伴自己去微信申请吧~

好的,接下来看 redirect_uri 这个参数,它指的是扫描二维码并授权之后,将会跳转到哪个网址中。这个参数同样需要我们在申请 appid 和 appserect 时指定的,所以各位小伙伴还是先申请之后再往下看吧。

如果实在没有的话,咱可以借用一下 优酷 的微信登陆 url

https://open.weixin.qq.com/connect/qrconnect?appid=wxfec7791666c961ae&redirect_uri=https%3A%2F%2Faccount.youku.com%2Fhavana_callback.htm%3FtargetUrl%3Dhttps%253A%252F%252Fcnpassport.youku.com%252Foauth_sign.htm%253Ftype%253Dweixin&response_type=code&state=idc_1WEVs9T15qk04MxAGzfyeSA&scope=snsapi_login#wechat_redirect

在此之前呢,我们一起把刚刚写的代码封装一下,用于加载指定的网页到我们自己的窗口中。

int loadTheWebPage(QString myUrl)
{
    LiveView->settings()->setAttribute(QWebEngineSettings::PluginsEnabled, true);
    LiveView->setAttribute(Qt::WA_DeleteOnClose);
    LiveView->load(QUrl(myUrl));
    LiveView->resize(500, 500);
    LiveView->show();

    return 0;
}

接下来,咱就来拼接要加载的链接地址,并调用这个函数

// 小伙伴自己去申请这两个值哦,我这个是不能直接用的,*是某个字符来的
QString AppId = "wxf***************7f";	
QString AppSecret = "1a6************************46";
QString RedirectUrl = "http://********";

this->LiveView = new QWebEngineView(this);
QString myurl = QString("https://open.weixin.qq/connect/qrconnect?appid=%1&redirect_uri=%2&response_type=code&state=idc_1qloO7huDcIYf9qpjYZ8WkA&scope=snsapi_login#wechat_redirect")
            .arg(AppId).arg(RedirectUrl);

loadTheWebPage(RequestUrl);

尝试过的小伙伴肯定知道了效果,这里就不放截图了。

但大家肯定很疑惑,因为这个效果就仅仅是跳转到我们所指定的网页罢了,仅仅扫了个码,登陆了个寂寞???



5. 登录过程

当然不是了,首先我们先明确一下我们所指的登录究竟是什么?

没错,获取当前扫码用户的预留在微信的个人信息,方便我们辨别用户对吧。那既然我们的最终目标是获取个人信息,那中间过程怎么实现呢?

让我们先来了解这一整套流程:

很显然,我们已经做完了第一步,第二步这 code 在哪儿呢?



6. 获取 code

这里使用的是优酷的那个微信登陆作为例子。

不知各位有没有注意到我们是不是有个槽函数在打印着什么东西,是的,它在兢兢业业的打印着每次加载完的网页网址。我们回头来看看这个打印结果。

刚开始显示二维码未扫码时打印的是这个:

Url =  "https://open.weixin.qq/connect/qrconnect?appid=wxfec7791666c961ae&redirect_uri=https%3A%2F%2Faccount.youku%2Fhavana_callback.htm%3FtargetUrl%3Dhttps%253A%252F%252Fcnpassport.youku%252Foauth_sign.htm%253Ftype%253Dweixin&response_type=code&state=idc_1WEVs9T15qk04MxAGzfyeSA&scope=snsapi_login#wechat_redirect" 

没错,这就是我们指定的链接地址,没什么问题,接着往下看。

扫描二维码并授权之后,网页跳转,打印的是这个:

Url =  "https://cnpassport.youku/oauth_sign.htm?type=weixin&code=031nU5000i96lL1LgG100cqBT02nU501&state=idc_1WEVs9T15qk04MxAGzfyeSA" 

欸?这里面好像有什么东西???

code=031nU5000i96lL1LgG100cqBT02nU501

哦吼,得来全不费工夫?藏在跳转之后的网页网址中了呀,那这样一来我们就可以很容易的获得它了,只需要将我们的打印网址的槽函数加一个判断再取出来就好了。

void OnLoadFinished()
{
    QString currentUrl = LiveView->url().toString();

    if(currentUrl.indexOf("code=") != -1)	// 如果含有 code= ,就把 code 的值取出来
    {
    	// 截取字符串操作,本人比较笨,硬截,方法多样可改进
        QString code = currentUrl.mid( currentUrl.indexOf("code=")+5, (currentUrl.indexOf("&s")-currentUrl.indexOf("code=")-5) );
		qDebug() << "code = " << code << endl;
    }
}

这样一来,我们就完成了第二步。

后面的步骤没有 appsecret 就做不了啦,所以没有这个的小伙伴先去申请吧,先写到这。



7. 获取 access_token

那我们继续,现在我们手头里已经有了 code ,appid , appsecret,接下来就是用这三者去换取我们的access_token 了,具体怎么操作呢?

查阅微信开发文档,发现是发送一个 get 请求,然后 access_token 就在回码当中。

这个 get 请求地址长这样:

https://api.weixin.qq.com/sns/oauth2/access_token?appid=%1&secret=%2&code=%3&grant_type=authorization_code

然后我们将 code ,appid , appsecret 分别填入到对应位置,就组成了一个完整的请求地址。

那么我们首先来解决如何发送一个 get 请求这个问题。
我们需要用到 QNetworkAccessManager 类来处理网络请求相关的事务,这个类里面有 get 函数用于向目标地址发送一个 get 请求,当然了,它同样也有一个 post 函数,用于发送一个 post 请求。

请求发送完,服务器会相应回码,QNetworkAccessManager 类中有一个响应完成信号:

[signal] void QNetworkAccessManager::finished(QNetworkReply *reply);

再来看看 get 请求函数原型:

QNetworkReply *QNetworkAccessManager::get(const QNetworkRequest &request);

由此可见,我们还要导入这些头文件

#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>

好的,那我们就来编写一个专门用来发送一个 get 请求的函数:

void sendAGetRequest(const QString &url)
{
	qDebug() << "url = " << url;

    manager = new QNetworkAccessManager();
    manager->get(QNetworkRequest(QUrl(url)));

    qDebug() << "Finished send a requset" << endl;
}

那么我们现在就可以直接发送一个 get 请求了:

int getAccessToken(const QString &appId, const QString &appSecret, const QString &code)
{
	QString toGetAccessToken = QString("https://api.weixin.qq/sns/oauth2/access_token?appid=%1&secret=%2&code=%3&grant_type=authorization_code")
            .arg(appId).arg(appSecret).arg(code);

    sendAGetRequest(toGetAccessToken);	// 调用一下上面的函数,发送 1 个 get 请求
    // 连接相应完成槽函数,若有回码,就在这个槽函数中接收
    connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(OnReplyFinshed(QNetworkReply*)));	

	return 0;
}

然后我们在槽函数中处理回文:

void OnReplyFinshed(QNetworkReply *reply)
{
    QVariant variant = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
    int status = variant.toInt();
    qDebug() << "status = " << status;		// http 状态码,据此来判断相应状态

    QTextCodec *codec = QTextCodec::codecForName("utf8");       //使用utf8编码,这样才可以显示中文
    QString all = codec->toUnicode(reply->readAll());

    qDebug() << all;	// 将回文打印出来

    reply->deleteLater();   //最后要释放reply对象
}

本文标签: 第三方过程QT