HTTP 摘要认证

news2024/11/17 6:38:53

文章目录

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


一、什么是摘要认证

摘要认证,即 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_OBJECT
    
   public:
    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) {  // 服务器返回401
            QString url = "/setup/system/update.php?app=set";
            QString user = "admin";
            QString psw = "12345";
            strAuth = checkRequest.reAuthenticate(url, user, psw, strRecv);  // 根据服务器定的规则,计算验证信息
            // 使用计算出来的验证信息,重新请求API
            CHttpRequest 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.coloradmin.cn/o/1573935.html

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

相关文章

10 Python进阶:MongoDB

MongoDb介绍 MongoDB是一个基于分布式架构的文档数据库&#xff0c;它使用JSON样式的数据存储&#xff0c;支持动态查询&#xff0c;完全索引。MongoDB是NoSQL数据库的一种&#xff0c;主要用于处理大型、半结构化或无结构化的数据。以下是MongoDB数据库的一些关键特点和优势&a…

【计算机毕业设计】宠物销售系统——后附源码

&#x1f389;**欢迎来到我的技术世界&#xff01;**&#x1f389; &#x1f4d8; 博主小档案&#xff1a; 一名来自世界500强的资深程序媛&#xff0c;毕业于国内知名985高校。 &#x1f527; 技术专长&#xff1a; 在深度学习任务中展现出卓越的能力&#xff0c;包括但不限于…

论文阅读——Sat2Vid

Sat2Vid: Street-view Panoramic Video Synthesis from a Single Satellite Image 提出了一种新颖的方法&#xff0c;用于从单个卫星图像和摄像机轨迹合成时间和几何一致的街景全景视频。 即根据单个卫星图像和给定的观看位置尽可能真实地、尽可能一致地合成街景全景视频序列。…

全面解析十七种数据分析方法,具象数据分析思维

本文干货信息汇总&#xff1a;FineBI自助式BI数据分析工具下载>>https://s.fanruan.com/vfp40FineBI数据分析模板库>>https://s.fanruan.com/fnbjg 一、介绍 在当今数据驱动的商业环境中&#xff0c;数据分析已经成为了企业获取竞争优势的关键工具。无论是为了优化…

ACT逻辑解析

ACT逻辑解析 ACT内核1. 整体过程&#xff1a;1.1 Action Chunking and Temporal Ensemble1.2 Modeling human data(人工示教数据建模)1.3 Implemention ACT1.4 ACT内核 现有模仿学习缺点&#xff1a;在细颗粒度的任务中需要有高频的控制和闭环反馈 1. 整体过程&#xff1a; …

Mysql5.7 yum 简单/快速安装

Centos7下MySql安装及配置过程&#xff0c;简单直装版 目录 操作步骤 一、检查linux是否已安装MySql二、清除MySQL&#xff08;适用重新安装&#xff09; 1、删除MySQL及其依赖包2、查询遗留的目录3、删除遗留的目录三、开始安装MySQL 1、下载并添加库2、安装MySQL包3、设置My…

PID控制有物理含义吗

PID控制有物理含义吗 一、背景 对于PID的初学者&#xff0c;经常会有疑惑&#xff0c;为什么位置的误差通过PID就变成了期望速度&#xff1f;他们之间有什么物理关系吗&#xff1f;还有对于无人机&#xff0c;为什么期望升力&#xff0c;又是期望加速度&#xff0c;又是期望油…

绝地求生:愉人不愚人!分享你的PUBG摸“愚”穿搭,赢精美套装好礼

活动简介 愚人节来啦&#xff01;为了和大家一起分享诙谐幽默的搞怪氛围&#xff0c;特此推出搞怪穿搭大会&#xff01;快来戴上你最喜爱的头套或面具一起来参加吧&#xff01;只要参与 #摸“愚”穿搭# 话题投稿&#xff0c;即有机会赢取魔力甜心萨莉套装1的奖励&#xff0c;也…

Composer Windows 安装

Composer 的下载地址为&#xff1a;Composer 1 运行安装程序 当启动安装程序后单击下一步继续。 选择 PHP 路径 如果你的计算机上没有安装 PHP 的话&#xff0c;Composer 的安装无法继续。 你需要选择你本地安装的 PHP 路径。 配置代理地址 默认的情况下&#xff0c;可以不…

外汇110:外汇交易不同货币类别及交易注意事项!

外汇市场是一个庞大而复杂的市场&#xff0c;其中有各种各样的货币品种。对于外汇投资者来说&#xff0c;了解外汇品种的特性和走势是比较重要的。1. 货币种类 外汇市场中的货币品种可以分为主要货币、次要货币和外围货币。 主要货币&#xff1a;主要指美元、欧元、英镑、日元、…

美国CPC认证是什么?为什么必须办理CPC认证呢?

美国CPC认证&#xff0c;全称为Childrens Product Certificate&#xff0c;是儿童产品认证的意思。它主要针对的是在美国市场销售的儿童产品&#xff0c;如玩具、家具、童车、餐椅、床上用品等。CPC认证要求产品安全性高&#xff0c;符合美国加州65、16 CFR等法规要求&#xff…

window安装maven和hadoop3.1.4

前面的文章已讲解如何安装idea和进行基本设置&#xff0c;本文主要带着大家安装配置好maven和hadoop. 大家不用去官网下载&#xff0c;直接使用我发给大家的压缩文件&#xff0c;注意解压后的文件夹不要放在中文目录下&#xff0c;课堂上我们讲解过原因。 这是我电脑上的路径&a…

vue3基础入门项目实战实例介绍

Vue 3 带来了许多新特性和性能优化&#xff0c;使得构建高效且可维护的前端应用变得更加容易。下面是一个简单的 Vue 3 基础项目实战实例介绍&#xff0c;帮助你入门&#xff1a; 项目概述 这个实战项目是一个简单的待办事项管理应用&#xff0c;用户可以添加、编辑和删除待办…

商业地产数字化是什么?又有哪些优势呢?

​一、什么是商业地产数字化 数字化是信息化的延伸与拓展。在企业完成信息化之后&#xff0c;对存储的信息的解析与挖掘&#xff0c;建立数据洞察&#xff0c;从而改变企业决策&#xff0c;打造全新的企业运作方式&#xff0c;实现数据化转型。 商业地产数字化是指将商业地产…

前端三剑客 —— JavaScript (第三节)

目录 内容回顾&#xff1a; 1.数据类型 2.常见运算符 数据类型转换 自动类型转换 强制类型转换 流程控制语句 顺序流程 选择流程 单分支 多分支 switch 循环流程 for循环 while循环 do...while循环 如何选择 continue和break 循环案例 内容回顾&#xff1a; …

Dapr(三) Dapr核心组件的使用一

结合前两期 Dapr(一) 基于云原生了解Dapr(Dapr(一) 基于云原生了解Dapr-CSDN博客) Dapr(二) 分布式应用运行时搭建及服务调用(Dapr(二) 分布式应用运行时搭建及服务调用-CSDN博客) 下篇推出dapr服务注册与发现&#xff0c;dapr组件绑定&#xff0c;dapr Actor功能。 目录 1.…

Java中的常用类详解(Math、Scanner、Random、String)

目录 一、Math&#xff08;数学类&#xff09; 自带常量 取整方法 三角函数方法 指数函数方法 其他方法 二、Scanner&#xff08;实用程序类&#xff09; 三、Random&#xff08;随机数类&#xff09; 四、String&#xff08;字符串类&#xff09; 获取相关 判断相关…

实践笔记-03 docker buildx 使用

docker buildx 使用 1.启用docker buildx2.启用 binfmt_misc3.从默认的构建器切换到多平台构建器3.1创建buildkitd.toml文件&#xff08;私有仓库是http没有证书的情况下&#xff0c;需要配置&#xff09;3.2创建构建器并使用新创建的构建器 4.构建多架构镜像并推送至harbor仓库…

清风DJ,DJ舞曲听不停

hi&#xff0c;大家好我是技术苟&#xff0c;每周准时上线为你带来实用黑科技&#xff01;由于公众号改版&#xff0c;现在的公众号消息已经不再按照时间顺序排送了。因此小伙伴们就很容易错过精彩内容。喜欢黑科技的小伙伴&#xff0c;可以将黑科技百科公众号设为标星&#xf…

如何选择适合智能型程控直流电子负载

在选择适合智能型程控直流电子负载时&#xff0c;需要考虑以下几个方面&#xff1a; 根据实际需求选择合适的负载容量&#xff0c;负载容量是指电子负载能够承受的最大电流和电压。一般来说&#xff0c;负载容量越大&#xff0c;价格越高。因此&#xff0c;在满足实际需求的前提…