Web API 2身份验证筛选器 - 当Authorization标头存在时,AuthenticateAsync不会触发

时间:2015-03-22 17:45:24

标签: android iis-7 asp.net-web-api2 http-basic-authentication

我有一个奇怪的问题,当我的本地IIS运行网站时,一个简单的身份验证过滤器不会触发。如果我发布到Azure,身份验证筛选器工作正常。所以我怀疑我的本地IIS设置,但除了在网站的身份验证设置下启用“基本身份验证”,我真的不知道它可能是什么设置。

我创建了一个空Web API 2网站,用于创建值控制器。然后,我为验证过滤器添加了以下样板代码: -

public class BasicAuthenticationAttribute : Attribute, IAuthenticationFilter
{

    public bool AllowMultiple { get { return false; } }

    public Task AuthenticateAsync(HttpAuthenticationContext context,
                                    CancellationToken cancellationToken)
    {
        var req = context.Request;
        // Get credential from the Authorization header 
        //(if present) and authenticate
        if (req.Headers.Authorization != null &&
            "Basic".Equals(req.Headers.Authorization.Scheme,
            StringComparison.OrdinalIgnoreCase))
        {
            if (TryValidateCredentials(req.Headers.Authorization.Parameter))
            {
                var claims = new List<Claim>()
                            {
                            new Claim(ClaimTypes.Name, "AuthenticatedUser"),
                            new Claim(ClaimTypes.Role, "user")
                            };
                var id = new ClaimsIdentity(claims, "Token");
                var principal = new ClaimsPrincipal(new[] { id });
                // The request message contains valid credential
                context.Principal = principal;
            }
            else
            {
                // The request message contains invalid credential
                context.ErrorResult = new UnauthorizedResult(
                    new AuthenticationHeaderValue[0], context.Request);
            }
        }
        return Task.FromResult(0);
    }
    private bool TryValidateCredentials(string creds)
    {
        string pair;

        try
        {
            pair = Encoding.UTF8.GetString(Convert.FromBase64String(creds));
        }
        catch (FormatException)
        {
            return false;
        }
        catch (ArgumentException)
        {
            return false;
        }
        var ix = pair.IndexOf(':');
        if (ix == -1) return false;
        var username = pair.Substring(0, ix);
        var pw = pair.Substring(ix + 1);
        if (username != "" && pw != "")
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
    {
        context.Result = new ResultWithChallenge(context.Result);
        return Task.FromResult(0);
    }
    public class ResultWithChallenge : IHttpActionResult
    {
        private readonly IHttpActionResult next;
        public ResultWithChallenge(IHttpActionResult next)
        {
            this.next = next;
        }
        public async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
        {
            var response = await next.ExecuteAsync(cancellationToken);
            if (response.StatusCode == HttpStatusCode.Unauthorized)
            {
                response.Headers.WwwAuthenticate.Add(
                    new AuthenticationHeaderValue("Basic", "Please supply valid credentials"));
            }
            return response;
        }
    }

}

然后我使用以下属性为ValuesController类添加前缀: -

[TestBA.Filters.BasicAuthentication]
[Authorize]

我的默认IIS7网站(Windows 7家庭高级版)指向项目文件夹,如果我运行并调试w3wp.exe(托管版v4),然后点击http://192.168.1.11/api/values网站会在AuthenticateAsync开始时出现断点被击中如果我从Android代码调用,我也会遇到相同的断点。但是,如果我使用AsyncHttpClient.setBasicAuth设置基本身份验证标头,或者手动添加标头,那么断点永远不会被命中,我立即得到未经授权的HTTP响应。如果我将网站发布到Azure,那么它可以正常工作,所以未经调用AuthenticateAsync的未经授权的响应只发生在我的本地IIS上。如果有帮助,这是Android代码: -

private void setBasicAuth(AsyncHttpClient client){
    client.setBasicAuth("test", "test");
    /*client.addHeader("Authorization",
                       "Basic " + android.util.Base64.encodeToString(
                           "test:test".getBytes(),
                           android.util.Base64.NO_WRAP
                           )
                      );*/
}

我甚至在Visual Studio社区2013中打开了所有可能的异常,看看我是否缺少运行时异常或本机代码异常,但没有。如果有任何相关性,我在Android上使用loopj库。此外,如果有任何相关性,我会在原生Android IDE“AIDE”上编写Android代码。 IIS日志显示请求正在进入并被401响应,无论我是否使用基本身份验证标头进行呼叫,因此请求在这两种情况下肯定都有效。

如果有人能够解释为什么在IIS的本地副本上的请求中指定了基本身份验证标头时,为什么Web API 2身份验证过滤器不会触发,那么我将非常感激。

1 个答案:

答案 0 :(得分:4)

我在我的工作电脑上重写了测试应用程序并且无法让它失败,所以这是一个区别点的情况。

答案其实非常明显。我在我的本地IIS上盲目启用了“基本身份验证”,因为我当然希望在我的Web API 2网站中使用基本身份验证。错误!在IIS中启用基本身份验证告诉IIS拦截并处理所有基本身份验证标头,而不将它们传递到网站。它实际上试图将用户名和密码与本地PC用户帐户匹配。我需要的是在IIS中禁用基本身份验证,然后允许授权HTTP标头传递到我的网站并导致AuthenticateAsync启动。