Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# HttpClientHandler RFC 7616摘要身份验证标头使用了错误的Uri_C#_Http_Httpclient_Flurl - Fatal编程技术网

C# HttpClientHandler RFC 7616摘要身份验证标头使用了错误的Uri

C# HttpClientHandler RFC 7616摘要身份验证标头使用了错误的Uri,c#,http,httpclient,flurl,C#,Http,Httpclient,Flurl,我试图访问Lighttpd服务器上的资源,该服务器强制要求完整请求URI与授权请求标头中的URI匹配。这是在中指定的 身份验证服务器必须确保指定的资源 “uri”参数与中指定的资源相同 请求行;如果不是,服务器应该返回400坏消息 请求错误。(由于这可能是攻击的症状,服务器 实现者可能想考虑记录这些错误。 从该字段中的请求URL复制信息的目的是 处理中间代理可能改变的可能性 客户的请求行。这改变了(但可能是语义上的 等效)请求不会产生与该请求相同的摘要 由客户计算 我使用的是(v1.4),它只是

我试图访问Lighttpd服务器上的资源,该服务器强制要求完整请求URI与授权请求标头中的URI匹配。这是在中指定的

身份验证服务器必须确保指定的资源 “uri”参数与中指定的资源相同 请求行;如果不是,服务器应该返回400坏消息 请求错误。(由于这可能是攻击的症状,服务器
实现者可能想考虑记录这些错误。 从该字段中的请求URL复制信息的目的是
处理中间代理可能改变的可能性
客户的请求行。这改变了(但可能是语义上的
等效)请求不会产生与该请求相同的摘要
由客户计算

我使用的是(v1.4),它只是HttpClient的包装器。然而,HttpClientHandler来自.Net

为什么它使用基本URI而不是完整URI?是虫子吗?如何使用完整的URI

我曾考虑将另一个HttpMessageHandler添加到管道中,并使用完整URI修改身份验证标头,但HttpClientHandler不允许您设置InnerHandler

完整的Uri应为

但这是出现在请求头中的内容:

授权:摘要 username=“user”,realm=“service”,nonce=“5b911545:EAF435212113E5E4B1CA253BD70FD90A”, uri=“/base/resource.cgi”,cnonce=“bf7cf40f1289bc10bd07e8bf4784159c”,nc=00000001,qop=“auth”,response=“cf3c731ec93f7e5928f19f880f8325ab”

这将导致400个错误请求响应

我的Flurl代码:

HttpClient工厂

    /// <summary>
    /// Custom factory to generate HttpClient and handler to use digest authentication and a continuous stream
    /// </summary>
    private class DigestHttpFactory : Flurl.Http.Configuration.DefaultHttpClientFactory
    {
        private CredentialCache CredCache { get; set; }

        public DigestHttpFactory(string url, string username, string password) : base()
        {
            Url = url;

            CredCache = new CredentialCache
            {
                { new Uri(Url), "Digest", new NetworkCredential(username, password) }
            };
        }

        private string Url { get; set; }

        public override HttpClient CreateHttpClient(HttpMessageHandler handler)
        {
            var client = base.CreateHttpClient(handler);
            client.Timeout = TimeSpan.FromMilliseconds(Timeout.Infinite); // To keep stream open indefinietly
            return client;
        }

        public override HttpMessageHandler CreateMessageHandler()
        {
            var handler = new HttpClientHandler
            {
                Credentials = CredCache.GetCredential(new Uri(Url), "Digest")
            };


            return handler;
        }
    }

看来,这确实是微软实施RFC的一大障碍:

System.Net类在“Uri”中不包含查询字符串 摘要身份验证标头的属性。这违反了法律 RFC和一些web服务器实现拒绝这些请求


这篇文章详细介绍了一项来自微软的解决方案。

看来,这确实是微软实施RFC的一个重要原因:

System.Net类在“Uri”中不包含查询字符串 摘要身份验证标头的属性。这违反了法律 RFC和一些web服务器实现拒绝这些请求


那篇文章详细介绍了一项工作。啊,希望我不必重新实现摘要认证。考虑到这是一个如此古老的问题,我怀疑微软会做任何事情。你认为你可以为你的很棒的库添加这样一个补丁吗:)?也许是作为一个更保守的方法的额外参数,或者也许我可以在一些pull请求中添加它?我不会做出任何承诺,但继续,请将这个问题链接回来。人们也在要求Windows身份验证,所以也许我可以在将来的版本中取消这两个功能。啊,希望我不必重新实现摘要身份验证。考虑到这是一个如此古老的问题,我怀疑微软会做任何事情。你认为你可以为你的很棒的库添加这样一个补丁吗:)?也许是作为一个更保守的方法的额外参数,或者也许我可以在一些pull请求中添加它?我不会做出任何承诺,但继续,请将这个问题链接回来。人们也在要求WindowsAuth,所以也许我可以在将来的版本中把这两个都删掉。
public class MyConnection
{
    public string BaseUrl => "http://base/resource.cgi";

    public async Task ConnectAsync(CancellationToken cancellationToken = default(CancellationToken))
    {
        ConnectionCancellation = new CancellationTokenSource();

        var url = BaseUrl
            .SetQueryParam("my", 1)
            .SetQueryParam("params", 2)

        FlurlHttp.ConfigureClient(url, client =>
        {
            client.Configure(settings =>
            {
                settings.HttpClientFactory = new DigestHttpFactory(url, Username, Password);
            });
        });

        try
        {
            using (var getResponse = url.GetAsync(cancellationToken, HttpCompletionOption.ResponseHeadersRead))
            {
                var responseMessage = await getResponse;

                using (var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(ConnectionCancellation.Token, cancellationToken))
                using (var stream = await responseMessage.Content.ReadAsStreamAsync())
                    await Process(stream, linkedCts.Token);
            }
        }
        catch (OperationCanceledException ex)
        {
            throw ex;
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }
}