首页 > 解决方案 > “WebRequest”对象如何确定要使用的“IAuthenticationModule”实现?

问题描述

我想使用 System.Net 的AuthenticationManager类来定义WebRequest的基本或不记名授权标头。

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

而且我认为必须通过给出在模块的“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;
    }
}

标签: c#authenticationauthorizationbasic-authenticationbearer-token

解决方案


AuthenticationManager 将始终按照注册的顺序调用所有 IAuthenticationModule,直到返回一个非 null Authorization 实例。

这个想法是每个 IAuthenticationModule 实现都应该根据他们能够做什么来验证挑战参数,如果它们不匹配则返回 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 标头的内容,这与您在 CredentialCache 中编写的“基本”无关


推荐阅读