HTTP 摘要认证

文章目录

  • 一、什么是摘要认证
  • 二、工作流程
  • 三、实例演示


一、什么是摘要认证

摘要认证,即 Digest Access Authentication,是一种HTTP身份验证机制,用于验证用户的身份。相较于基本认证(Basic Authentication)使用用户名密码的方式,提供了更高的安全性和灵活性。

二、工作流程

HTTP Digest Access Authentication 的工作流程如下:

  1. 客户端发送一个未经认证的请求到服务器
  2. 服务器返回一个 HTTP 401 Unauthorized 响应,其中包含一个 “WWW-Authenticate” 头部字段,用来表示所使用的认证方式(通常是 Digest),以及一些额外的参数,如 realm(领域)、nonce(随机数)等
  3. 客户端收到 401 响应后,会根据服务器提供的信息,计算出一个摘要(digest)。客户端将摘要信息添加到请求中的 “Authorization” 头部字段中,重新发送请求到服务器
  4. 服务器收到带有摘要的请求后,会使用相同的算法计算出一个期望的摘要,并与客户端提供的摘要进行比较。如果两者一致,则服务器会接受该请求,返回请求的资源;否则,服务器拒绝请求,可能返回 401 或其他适当的响应

三、实例演示

客户端调用服务器 API 发送请求:

class CHttpRequest : public QObject {Q_OBJECTpublic:int sendFile(const QString &strUrl, QString &strFile, QString &strAuth, QString &recvMessage) {m_bNeedAuth = false;disconnect(m_pNetworkManager, SIGNAL(finished(QNetworkReply *)), this, SLOT(slot_requestFinished(QNetworkReply *)));  // 请求完成信号connect(m_pNetworkManager, SIGNAL(finished(QNetworkReply *)), this, SLOT(slot_requestRet_Syn(QNetworkReply *)));// 构造请求头QNetworkRequest netRequest(strUrl);QString boundary = "----WebKitFormBoundaryyYCL2Hd3ZwCR4KhI";QString contenType = "multipart/form-data; boundary=" + boundary;netRequest.setHeader(QNetworkRequest::ContentTypeHeader, contenType);if (strAuth != "") {netRequest.setRawHeader("Authorization", strAuth.toLatin1());}// 打开文件QFile file(strFile);if (!file.open(QIODevice::ReadOnly)) {return -1;}// 构建请求数据strFile.remove(0, strFile.lastIndexOf('/') + 1);QString text = "Content-Disposition: form-data; name=\"fimage\"; filename=\"" + strFile + "\"\r\n";QByteArray data;data.append("--" + boundary + "\r\n");data.append(text);data.append("Content-Type: application/octet-stream\r\n\r\n");data.append(file.readAll());data.append("\r\n--" + boundary + "--\r\n");// 发送POST请求m_pNetworkReply = m_pNetworkManager->post(netRequest, data);// ...省略部分代码recvMessage = this->m_strRet;if (m_bNeedAuth) {return 401;}return m_loop_flag;}public slots:// 接收服务器返回信息void slot_requestRet_Syn(QNetworkReply *reply) {// ...省略部分代码QByteArray resultContent = reply->readAll();QTextCodec *pCodec = QTextCodec::codecForName("UTF-8");QString strResult = pCodec->toUnicode(resultContent);int nHttpCode = reply>attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); // http返回码if (nHttpCode == 200) {  // 请求成功} else if (nHttpCode == 401) {  // 请求失败,想要认证// 获取服务器返回的WWW-Authenticate认证信息QList<QByteArray> headers = reply->rawHeaderList();for (QList<QByteArray>::const_iterator iter = headers.constBegin(); iter != headers.constEnd(); ++iter) {qDebug() << *iter << ":" << reply->rawHeader(*iter);QString msg = *iter;if (msg.contains("WWW-Authenticate")) {strResult = reply->rawHeader(*iter);}}} else {  // 其他错误}}public:// 计算验证信息的函数,这里的计算规则是我这台服务的规定,大家处理的时候要根据自己服务器的规则去处理QString reAuthenticate(QString &strUrl, QString &strUser, QString &strPsw, QString &httpHeadFromServer) {QString realm, qop, nonce, opaque;int lastIndex = httpHeadFromServer.lastIndexOf("Digest realm=");httpHeadFromServer = httpHeadFromServer.mid(lastIndex);realm = httpHeadFromServer.section("realm=\"", 1, 1).split('"').first();qop = httpHeadFromServer.section("qop=\"", 1, 1).split('"').first();nonce = httpHeadFromServer.section("nonce=\"", 1, 1).split('"').first();opaque = httpHeadFromServer.section("opaque=\"", 1, 1).split('"').first();QString A1 = strUser + ":" + realm + ":" + strPsw;QByteArray hashedA1 = QCryptographicHash::hash(A1.toUtf8(), QCryptographicHash::Sha256);QString strHashA1 = hashedA1.toHex();QString A2 = "POST:" + strUrl;QByteArray hashedA2 = QCryptographicHash::hash(A2.toUtf8(), QCryptographicHash::Sha256);QString strHashA2 = hashedA2.toHex();QString response = strHashA1 + ":" + nonce + ":00000001:b985236c7eb52970:auth:" + strHashA2;QByteArray hashedRes = QCryptographicHash::hash(response.toUtf8(), QCryptographicHash::Sha256);QString strRes = hashedRes.toHex();QString strAuth = " Digest username=\"" + strUser + "\", realm=\"" + realm + "\", nonce=\"" + nonce + "\", uri=\"" +strUrl + "\", algorithm=SHA-256, response=\"" + strRes + "\", opaque=\"" + opaque + "\", qop=" + qop +", nc=00000001, cnonce=\"b985236c7eb52970\"";return strAuth;  // 处理好的认证信息}
};int main() {QString strAuth = "";CHttpRequest checkRequest;QString strURL = "http://172.16.26.165/setup/system/update.php?app=set";int ret = checkRequest.sendFile(strURL, strTmpFile, strAuth, strRecv);  // 第一次调用API时,认证信息strAuth是空的if (ret == 401) {  // 服务器返回401QString url = "/setup/system/update.php?app=set";QString user = "admin";QString psw = "12345";strAuth = checkRequest.reAuthenticate(url, user, psw, strRecv);  // 根据服务器定的规则,计算验证信息// 使用计算出来的验证信息,重新请求APICHttpRequest checkRequest2;if (checkRequest2.sendFile(strURL, strTmpFile, strAuth, strRecv) != -1) {emit msgUpgradeSta(this, Upgrade_Success);} else {emit msgUpgradeSta(this, Upgrade_Fail);}return 0;}return 0;
}

如上代码,客户端想通过 HTTP POST 请求,发送一个文件给服务器。第一次调用 API 的时候,没有带上验证信息 Authorization,服务器返回 401 错误,并且在返回的 HTTP 头部信息中带有 WWW-Authenticate 认证信息:

HTTP/1.1 401 Unauthorized
Set-Cookie: PHPSESSID=984d2f37f1611d4848518ca643ccbfa0; path=/; HttpOnly
Set-Cookie: PHPSESSID=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
WWW-Authenticate: Digest realm="N5M-6S335",algorithm="MD5",qop="auth",nonce="6444da9264a78",opaque="51d97021ccdf09ef7a8da27e8193cabf"
WWW-Authenticate: Digest realm="N5M-6S335",algorithm="SHA-256",qop="auth",nonce="6444da9264a78",opaque="51d97021ccdf09ef7a8da27e8193cabf"
Content-type: text/html; charset=UTF-8
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Content-Length: 0
Date: Sun, 23 Apr 2023 07:13:21 GMT
Server: WintenDolighttpd/1.4.67

在 slot_requestRet_Syn 函数中截取 WWW-Authenticate 的内容(可以看到有两种加密方式,MD5 和 SHA-256)。获取到需要的验证信息后,main 函数调用 reAuthenticate 函数,根据服务器定的规则进行验证信息的处理,这里选择 SHA-256 的加密方式,所以代码里截取出WWW-Authenticate: Digest realm="N5M-6S335",algorithm="SHA-256",qop="auth",nonce="6444da9264a78",opaque="51d97021ccdf09ef7a8da27e8193cabf这一行信息,再分别截取出 realm、qop 等等这些字段,根据规则进行 SHA-256 加密,最终得出认证信息。最后,main 函数重新发送 HTTP 请求,在请求头的 Authorization 字段加上这串验证信息:

示例图片

这样,就可以成功请求服务器了。文中用到的 HTTP 请求类,可以到点击这里下载。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/596660.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

相机标定——四个坐标系介绍

世界坐标系(Xw,Yw,Zw) 世界坐标系是一个用于描述和定位三维空间中物体位置的坐标系&#xff0c;通常反映真实世界下物体的位置和方向。它是一个惯性坐标系&#xff0c;被用作整个场景或系统的参考框架。在很多情况下&#xff0c;世界坐标系被认为是固定不变的&#xff0c;即它…

解码mp4文件分别存储为pcm,yuv文件

// 解码分别写入对应文件 #include "myLog.h" #include <iostream>extern "C" { #include <libavformat\avformat.h> #include <libavutil\avutil.h> #include <libavcodec\avcodec.h> #include <libavutil\imgutils.h> #in…

华为ensp中高级acl (控制列表) 原理和配置命令 (详解)

作者主页&#xff1a;点击&#xff01; ENSP专栏&#xff1a;点击&#xff01; 创作时间&#xff1a;2024年4月6日23点18分 高级acl&#xff08;Access Control List&#xff09;是一种访问控制列表&#xff0c;可以根据数据包的源IP地址、目标IP地址、源端口、目标端口、协议…

多路转接-epoll/Reactor(2)

epoll 上次说到了poll&#xff0c;它存在效率问题&#xff0c;因此出现了改进的poll----epoll。 目前epoll是公认的效率最高的多路转接的方案。 快速了解epoll接口 epoll_create&#xff1a; 这个参数其实已经被废弃了。 这个值只要大于0就可以了。 这是用来创建一个epoll模…

应用性能分析工具CPU Profiler

简介 本文档介绍应用性能分析工具CPU Profiler的使用方法&#xff0c;该工具为开发者提供性能采样分析手段&#xff0c;可在不插桩情况下获取调用栈上各层函数的执行时间&#xff0c;并展示在时间轴上。 开发者可通过该工具查看TS/JS代码及NAPI代码执行过程中的时序及耗时情况…

torchvision中的数据集使用

torchvision中的数据集使用 使用和下载CIFAR10数据集 输出测试集中的第一个元素&#xff08;输出img信息和target&#xff09; 查看分类classes 打断点–>右键Debug–>找到classes 代码 import torchvisiontrain_set torchvision.datasets.CIFAR10(root"./data…

【PyQt5篇】使用QtDesigner添加控件和槽

文章目录 &#x1f354;使用QtDesigner进行设计&#x1f6f8;在代码中添加信号和槽 &#x1f354;使用QtDesigner进行设计 我们首先使用QtDesigner设计界面 得到代码login.ui <?xml version"1.0" encoding"UTF-8"?> <ui version"4.0&q…

基于Springboot中小企业设备管理系统设计与实现(论文+源码)_kaic

摘 要 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;各行各业相继进入信息管理时代&a…

html骨架以及常见标签

推荐一个网站mdn。 html语法 双标签&#xff1a;<标签 属性"属性值">内容</标签> 属性&#xff1a;给标签提供附加信息。大多数属性以键值对的形式存在。如果属性名和属性值一样&#xff0c;可以致谢属性值。 单标签&#xff1a;<标签 属性"属…

C++ 【桥接模式】

简单介绍 桥接模式属于 结构型模式 | 可将一个大类或一系列紧密相关的类拆分 为抽象和实现两个独立的层次结构&#xff0c; 从而能在开发时分别使用。 聚合关系&#xff1a;两个类处于不同的层次&#xff0c;强调了一个整体/局部的关系,当汽车对象销毁时&#xff0c;轮胎对象…

记录重装ubuntu系统

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言无法进入ubuntu图形化界面进入ubuntu的tty模式开始解决误打误撞进入X-Window界面&#xff0c;拷贝ubuntu系统文件重装ubuntu系统 前言 提示&#xff1a;这里可…

面试(04)————JavaWeb

1、网络通讯部分 1.1、 TCP 与 UDP 区别&#xff1f; 1.2、什么是 HTTP 协议&#xff1f; 1.3、TCP 的三次握手&#xff0c;为什么&#xff1f; 1.4、HTTP 中重定向和请求转发的区别&#xff1f; 1.5、 Get 和 Post 的区别&#xff1f; 2、cookie 和 session 的区别&am…