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.mzph.cn/news/796482.shtml

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

相关文章

Qt之信号和槽的机制

前言 在 C 中&#xff0c;对象与对象之间产生联系要通过调用成员函数的方式。但是在 Qt中&#xff0c;Qt提供了一种新的对象间的通信方式&#xff0c;即信号和槽机制。在GUI编程中&#xff0c;通常希望一个窗口部件的一个状态的变化会被另一个窗口部件知道&#xff0c;为…

12.自定义的多帧缓存架构

1.简介 在数字图像处理中&#xff0c;经常需要用到的一个架构就是多帧缓存。视频流中需要用到多帧缓存来防止帧撕裂现象&#xff0c;图像处理中也需要帧差法来做移动目标检测。因此一个多帧缓存架构在图像系统的设计中是十分重要的。 2.多帧缓存 在视频流中&#xff0c;通常不…

前端开发全景指南:语言与框架的精粹

&#x1f31f; 前言 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; &#x…

解决IDEA下载mysql驱动太慢

下载驱动 下载页 解压后&#xff0c;提取**.jar**文件&#xff0c;放到一个目录下(你自己决定这个目录) 打开IDEA项目&#xff0c;点击右侧的数据库选项卡 在打开的页面&#xff0c;点击号 依次选择&#xff1a;数据源->MySQL 在弹出的页面&#xff0c;依次选择&#…

mysql表字段长度扩容分析--MySQL什么情况下拓展字段长度会锁表?

MySQL什么情况下拓展字段长度会锁表&#xff1f; 原生MySQL只支持不跨越256字节的在线扩展&#xff08;online&#xff09;&#xff0c;对于跨越256字节的扩展只支持复制方式&#xff08;copy&#xff09;&#xff0c;扩展时需要锁表且禁止对数据表进行写操作。 字符串的字段是…

Quantinuum与微软携手突破:开创容错量子计算新纪元

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

腾讯云轻量服务器流量不够用了会怎么样?

腾讯云轻量应用服务器是限制月流量的&#xff0c;如果当月流量不够用了&#xff0c;流量超额了怎么办&#xff1f;流量超额后&#xff0c;需要另外支付流量费&#xff0c;如果你的腾讯云账号余额&#xff0c;就会自动扣除对应的流量费&#xff0c;如果余额不足&#xff0c;轻量…

YOLOv7原创独家改进: 小目标 | 注意力 |卷积和注意力融合模块(CAFMAttention) | 2024年4月最新成果

💡💡💡本文独家改进:卷积和注意力融合模块(CAFMAttention),增强对全局和局部特征的提取能力,2024年最新的改进思路 💡💡💡创新点:卷积和注意力巧妙设计 💡💡💡如何跟YOLOv8结合:1)放在backbone后增强对全局和局部特征的提取能力;2)放在detect前面,增…

深入浅出 -- 系统架构之负载均衡Nginx资源压缩

一、Nginx资源压缩 建立在动静分离的基础之上&#xff0c;如果一个静态资源的Size越小&#xff0c;那么自然传输速度会更快&#xff0c;同时也会更节省带宽&#xff0c;因此我们在部署项目时&#xff0c;也可以通过Nginx对于静态资源实现压缩传输&#xff0c;一方面可以节省带宽…

【Java网络编程】HTTP超文本传输协议

一、HTTP超文本传输协议 HTTP全称为Hyper Text Transfer Protocol超文本传输协议&#xff0c;它是基于TCP传输协议构建的应用层协议&#xff0c;作为支撑万维网www的核心协议&#xff0c;为了保证其效率及处理大量事务的能力&#xff0c;因此在设计时&#xff0c;HTTP被制定成为…

lua学习笔记5(分支结构和循环的学习)

print("*****************分支结构和循环的学习******************") print("*****************if else语句******************") --if 条件 then end a660 b670 --单分支 if a<b thenprint(a) end --双分支 if a>b thenprint("满足条件")…

C#操作MySQL从入门到精通(5)——查询数据

前言 在和MySql数据库交互的过程中,查询数据是使用最频繁的操作,本文详细介绍了查询数据的各种操作,包括查询一列数据、 查询两列数据、查询所有列数据、查询不重复的数据、查询指定行数据,绝对是C#操作MySql数据库史上最详细教程,能够帮助小白快速入门以及将这些功能迅速…

京东云4C8G服务器优惠价格418元1年,轻量云主机4核8G配置

京东云服务器优惠活动4C8G服务器配置418元一年&#xff0c;1899元3年&#xff0c;配置为轻量云主机4C8G-180G SSD系统盘-5M带宽-500G月流量&#xff0c;京东云服务器活动页面 jdyfwq.com 可以查看京东云服务器详细配置和精准报价单&#xff0c;活动打开如下图&#xff1a; 轻量…

sharding‐jdbc之分库分表实战

数据库表结构 店铺数据库 SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS 0;-- ---------------------------- -- Table structure for region -- ---------------------------- DROP TABLE IF EXISTS region; CREATE TABLE region (id bigint(20) NOT NULL COMMENT id,region_…

上位机图像处理和嵌入式模块部署(qmacvisual实时视频)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 前面我们测试和练习的时候&#xff0c;大部分情况下都是利用图像进行测试的&#xff0c;但是实际情况下&#xff0c;或者准确一点说&#xff0c;工…

android 制作登录页

项目需要可以直接copy layout.xml <?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"…

华为汽车的“计算+通信”电子电气架构

文章目录 整车结构 硬件平台 软件平台 总结展望 整车EEA&#xff08;电子电气架构&#xff09;&#xff0c;按照博世提出的演进路径&#xff0c;大致可以划分为四个阶段&#xff1a;分布式模块阶段、区域控制阶段、中央计算阶段、云计算阶段。示例如下&#xff1a; 本文选取…

【Node.js】短链接

原文链接&#xff1a;Nodejs 第六十二章&#xff08;短链接&#xff09; - 掘金 (juejin.cn) 短链接是一种缩短长网址的方法&#xff0c;将原始的长网址转换为更短的形式。短链接的主要用途之一是在社交媒体平台进行链接分享。由于这些平台对字符数量有限制&#xff0c;长网址可…

c# wpf LiveCharts 绑定 简单试验

1.概要 c# wpf LiveCharts 绑定 简单试验 2.代码 <Window x:Class"WpfApp3.Window2"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d"http://schem…

K8S基于containerd做容器从harbor拉取镜

实现创建pod时&#xff0c;通过指定harbor仓库里的镜像来运行pod 检查&#xff1a;K8S是不是用containerd做容器运行时&#xff0c;以及containerd的版本是不是小于1.6.22 kubectl get nodes -owide1、如果containerd小于 1.6.22&#xff0c;需要先升级containerd 先卸载旧的…