"WebRequest" 对象如何确定要使用的 "IAuthenticationModule" 实现?

How "WebRequest" object determine the "IAuthenticationModule" implementation to use?

我想使用 System.Net 的 AuthenticationManager class to define the basic or bearer authorization header of a WebRequest

AuthenticationManager 提供了一个 Register 方法来添加一个新模块(IAuthenticationModule 的实现)。这表明可以注册多个模块,并且有一种方法可以 select 其中一个模块。

而且我认为模块 selection 必须通过提供在模块的 "AuthenticationType" 属性 中定义的值来完成。我在传递给我的 "WebRequest".

CredentialCache 中定义了它

我尝试创建并保存 2 个模块:

然后我使用以下代码将我的 2 个模块保存在 AuthenticationManager 中:

// I remove the previous basic module 
AuthenticationManager.Unregister("Basic");

// And i register my 2 modules
AuthenticationManager.Register(customBasicModule);
AuthenticationManager.Register(customBearerModule);

但似乎这总是第一个被调用的记录模块。

我的测试代码:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://example.com");

var cache = new CredentialCache();
cache.Add(new Uri("http://example.com"), "Basic", new NetworkCredential("user", "password"));

request.Method = "GET";    
request.Credentials = cache;

HttpWebResponse response = (HttpWebResponse)request.GetResponse();

我希望调用 "customBasicModule",因为我在该模块的 属性 "AuthenticationType" 和 "CredentialCache" 中指示了 "Basic"。 但是如果我先注册"customBearerModule",它就会被调用。

模块:

public class BasicAuthenticationModule : IAuthenticationModule
{
    private const string BASIC_SCHEME = "Basic";

    public bool CanPreAuthenticate => false;

    public string AuthenticationType => BASIC_SCHEME;

    public Authorization Authenticate(string challenge, WebRequest request, ICredentials credentials)
    {
        // Some code to get Basic from ICredentials
    }

    public Authorization PreAuthenticate(WebRequest request, ICredentials credentials)
    {
        return null;
    }
}

public class BearerAuthenticationModule : IAuthenticationModule
{
    private const string BEARER_SCHEME = "Bearer";

    public bool CanPreAuthenticate => false;

    public string AuthenticationType => BEARER_SCHEME;

    public Authorization Authenticate(string challenge, WebRequest request, ICredentials credentials)
    {
        // Some code to get Bearer from ICredentials
    }

    public Authorization PreAuthenticate(WebRequest request, ICredentials credentials)
    {
        return null;
    }
}

AuthenticationManager 将始终按照注册的顺序调用所有 IAuthenticationModule,直到一个 return 非空授权实例。

这个想法是每个 IAuthenticationModule 实现都应该根据它们能够做什么来验证挑战参数,如果它们不匹配,return null。

所以您的实施应该参考

public class BasicAuthenticationModule : IAuthenticationModule
{
    private const string BASIC_SCHEME = "Basic";

    public bool CanPreAuthenticate => false;

    public string AuthenticationType => BASIC_SCHEME;

    public Authorization Authenticate(string challenge, WebRequest request, ICredentials credentials)
    {
        if (!challenge.StartWith(BASIC_SCHEME)) return null;
        // Some code to get Basic from ICredentials
    }

    public Authorization PreAuthenticate(WebRequest request, ICredentials credentials)
    {
        return null;
    }
}

public class BearerAuthenticationModule : IAuthenticationModule
{
    private const string BEARER_SCHEME = "Bearer";

    public bool CanPreAuthenticate => false;

    public string AuthenticationType => BEARER_SCHEME;

    public Authorization Authenticate(string challenge, WebRequest request, ICredentials credentials)
    {
        if (!challenge.StartWith(BEARER_SCHEME)) return null;
        // Some code to get Bearer from ICredentials
    }

    public Authorization PreAuthenticate(WebRequest request, ICredentials credentials)
    {
        return null;
    }
}

另请注意,挑战是服务器在第一次未授权响应(401)后发送的 WWW-Authenticate header 的内容,与 "basic" 无关你写在 CredentialCache