ASP.Net Web API - 授权标题空白

nic*_*son 7 asp.net rest asp.net-mvc-4 asp.net-web-api

我不得不使用.NET(最初用Ruby编写)重写现有的REST API.从客户端的角度来看,它必须与旧API完全相同 - 即客户端代码不必更改.当前的API需要基本身份验证.因此,要调用旧API,以下工作完美: -

        var wc = new System.Net.WebClient();
        var myCache = new CredentialCache();
        myCache.Add(new Uri(url), "Basic", new NetworkCredential("XXX", "XXX"));
        wc.Credentials = myCache;
        var returnBytes = wc.DownloadData("http://xxxx");
Run Code Online (Sandbox Code Playgroud)

(出于安全原因,我不得不省略真实的URL /用户名/密码等).

现在我正在使用带有MVC4的ASP.Net Web API编写新的API.我有一个奇怪的问题,找不到其他人有完全相同的问题.为了支持基本身份验证,我遵循了以下指南:

http://sixgun.wordpress.com/2012/02/29/asp-net-web-api-basic-authentication/

有一件事,我把代码放在Application_Start()事件中的Global.asax.cs文件中的"钩子处理程序"中(我没猜到,所以我猜).

无论如何,如果我使用上面的代码调用我的API(我已在IIS中部署),Authorization标头始终为null,并且上面的失败,401 Unauthorized.但是,如果我使用此代码手动设置标头,它可以正常工作 - 即授权标头现在存在,我能够验证用户.

    private void SetBasicAuthHeader(WebClient request, String userName, String userPassword)
    {
        string authInfo = userName + ":" + userPassword;
        authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo));
        request.Headers["Authorization"] = "Basic " + authInfo;
    }
   .......
    var wc = new System.Net.WebClient();
    SetBasicAuthHeader(request, "XXXX", "XXXX");
    var returnBytes = wc.DownloadData("http://xxxx");
Run Code Online (Sandbox Code Playgroud)

虽然这有效,但对我来说并不好,因为现有API的现有用户不会手动设置标题.

阅读基本身份验证的工作原理,初始请求是匿名的,然后客户端返回401,然后客户端将再次尝试.但是,如果我在代码中添加一个断点,它将永远不会在Antony的示例中再次出现代码.我期待我的断点被击中两次.

任何想法我怎么能让这个工作?

Kur*_*ler 9

你期待正确的行为.System.Net.WebClient在初始请求时不会自动包含Authorization标头.它只会在响应正确挑战时发送它们,据我所知,这是一个401状态代码一个正确的WWW-Authenticate标头.有关详细信息,请参见此处此处.

我假设您的基本身份验证处理程序未返回WWW-Authenticate标头,因此WebClient甚至从未尝试在第二个请求上发送凭据.您应该可以在Fiddler或类似工具中观看此内容.

如果您的处理程序执行了类似的操作,您应该看到WebClient方法正常工作:

//if is not authenticated or Authorization header is null
return base.SendAsync(request, cancellationToken).ContinueWith(task =>
    {
        var response = task.Result;
        response.StatusCode = HttpStatusCode.Unauthorized;
        response.Headers.Add("WWW-Authenticate", "Basic realm=\"www.whatever.com\"");
        return response;
    });

//else (is authenticated)
return base.SendAsync(request, cancellationToken);
Run Code Online (Sandbox Code Playgroud)

正如您所注意到的,如果您在每个请求中都包含Authorization标头(就像您在替代方法中所做的那样),那么您的处理程序已经按原样运行.所以它可能就足够了 - 它不适用于以相同方式运行的WebClient和其他客户端.