Indy TIdHTTP URI,登录名/密码无效

 你虚伪的敷衍 发布于 2023-02-10 12:19

我正在编写一个HTTP API包装器来集成特定的IP摄像头.部分过程需要URI中的登录凭据,例如:

http://user:pass_with_#_sign@address:port/somespecificpath/

我正在使用Indy TIdHTTP.Get将请求发送到设备.但是,密码由"#"字符组成.如果此URI放在任何具有普通密码的浏览器中,则该#字符会将其抛出.因此,我需要将密码编码#%23...

http://user:pass_with_%23_sign@address:port/somespecificpath/

当我将此URI粘贴到任何浏览器中时,它会成功登录并执行所需的操作.但是,当我传入完全相同的URI时TIdHTTP.Get,它无法成功登录,因此只要密码包含#(或%23),我就无法做任何事情.将密码更改为不包含#一个解决方案太过于草率.Indy必须用这个URI /密码弄乱一些东西.

这是Indy中的一个错误,还是我需要做些什么来让Indy接受这样的编码密码?


UPDATE

我在其中一个摄像头上添加了一个用户名和密码的新帐户,没有任何需要编码的特殊字符,并且身份验证仍然无效.好像Indy正在从URI中完全剥离登录凭据,甚至不发送这些凭据.接下来我需要做的是监视实际发送的URI.


更新2

我通过WireShark进行了数据包捕获,并验证了凭证...user:pass@...甚至没有被发送 - 它们被从Indy实际发送的URI中删除.


更新3

TLama建议我捕获使用浏览器时发送的内容.我试过这个,当然即使使用浏览器,捕获也不会显示这些登录凭据......即使它可以在浏览器中运行.因此,我必须找出另一种方法来确定是否发送了这些凭据.


更新4

我尝试(在看到Remy的回答之前)在URI中提供这些凭据,Request.UsernameRequest.Password不是在URI中,我仍然没有成功.我一直从设备上取回"未经授权".


更新5

此API的文档提到与本段以外的用户身份验证无关的任何内容:

Grandstream Video Surveillance API(应用程序编程接口)支持HTTP 1.0协议(RFC1945).本文档通过支持的GET/POST方法详细说明了客户端功能的参数.用户需要管理员权限才能检索或设置参数.

在那方面,我确实将TIdHTTP协议版本切换为1.0.


更新6

希望最后一次更新需要......我对浏览器(Chrome)和浏览器之间的数据包捕获进行了另一次比较TIdHTTP.铬实际上发送两个请求,第一个不具有任何凭证,但在第二个请求有一个在首部的节点Authorization: Basic...Credentials: User:Pass,而使用TIdHTTP只发送在没有这些凭证1个单个请求.


更新7

7是一个幸运数字:-)我刚刚意识到,我对设备的第一个请求返回"未授权",但我所做的所有后续请求(使用相同的TIdHTTP实例)都是成功的!所以回到我之前的更新,就像我在浏览器捕获中看到的那样,它需要第二次重复请求才能工作.

1 个回答
  • #在URL的片段部分之前的URL中是非法字符,这就是为什么它必须%23在URL的其他区域中使用时进行编码的原因.

    用户名/密码实际上不是真实URL的一部分,这就是为什么在TIdHTTP将URL发送到服务器时被剥离的原因(监视任何Web浏览器的流量,您将看到同样的事情发生).

    要使用HTTP身份验证TIdHTTP,您需要使用TIdHTTP.Request.UsernameTIdHTTP.Request.Password属性(并且您不需要对值进行URL编码),例如:

    IdHTTP1.Request.Username := 'user';
    IdHTTP1.Request.Password := 'pass_with_#_sign';
    IdHTTP1.Get('http://address:port/somespecificpath/');
    

    如果您传递的URL中包含已编码的用户名/密码,TIdHTTP则会删除这些值并将其移动到Request.UsernameRequest.Password您的属性,但它们将保持原始编码格式,例如:

    IdHTTP1.Get('http://user:pass_with_%23_sign@address:port/somespecificpath/')
    // this will set Request.Username to 'user',
    // Request.Password to 'pass_with_%23_sign', and
    // send a request for 'http://address:port/somespecificpath/'
    

    如果您有一个编码的URL开头,您可以使用TIdURI该类在调用之前手动解码它TIdHTTP.Get(),例如:

    var
      RequestUrl: string;
      Uri: TIdURI;
    begin
      RequestUrl := 'http://user:pass_with_%23_sign@address:port/somespecificpath/';
      ...
      Uri := TIdURI.Create(RequestURL);
      try
        IdHTTP1.Request.Username := TIdURI.URLDecode(Uri.UserName);
        IdHTTP1.Request.Password := TIdURI.URLDecode(Uri.Password);
        RequestURL := Uri.URI;
      finally
        Uri.Free;
      end;
      IdHTTP1.Get(RequestUrl);
      ...
    end;
    

    更新:无论哪种方式,请确保您的子句中有适当的IdAuthentication...单位或IdAllAuthentications单位,uses以启用Indy的HTTP身份验证类TIdHTTP.

    2023-02-10 12:22 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有