2012-04-18 143 views
7

我不得不使用.NET重新编写现有的REST API(最初使用Ruby编写)。从客户的角度来看,它必须以与旧API完全相同的方式工作 - 即客户端代码不需要改变。当前的API需要基本认证。所以叫旧的API,下面完美的作品: -ASP.Net Web 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"); 

(我不得不ommit真实的URL /用户名/密码,出于安全考虑等)。

现在我正在使用ASP.Net Web API和MVC4编写新API。我有一个奇怪的问题,并找不到任何人有完全相同的问题。为了支持基本身份验证,我按照这里的准则:

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

有一两件事,我把代码为“钩在处理程序”,在在Application_Start中的Global.asax.cs文件()事件(没有解释,所以我猜)。

无论如何,如果我使用上面的代码调用我的API(我已经部署在IIS中),授权标头始终为空,并且上面的401未授权失败。但是,如果我使用此代码手动设置标题,它将正常工作 - 即授权标题现在存在,并且我可以对用户进行身份验证。

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"); 

虽然这样的作品,它没有对我很好,因为现有的API的现有用户不会手动设置的头。

阅读基本身份验证如何工作,初始请求是匿名的,然后客户端返回401,然后客户端打算再次尝试。但是,如果我在代码中放置了一个断点,它在Antony的例子中将不会再次触发代码。我期待着我的断点被击两次。

任何想法,我可以得到这个工作?

回答

9

你在期待正确的行为。在初始请求时,System.Net.WebClient不会自动包含授权标头。它只在适当地被响应挑战时发送它们,据我所知,它是一个401状态码一个正确的WWW-Authenticate头。有关更多信息,请参见herehere

我假设你的基本身份验证处理程序没有返回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); 

正如你注意到,如果包括在每个请求的Authorization头(就像你在你的另一种方法一样),然后你的处理程序已经按原样工作。所以这可能就足够了 - 它不仅仅适用于以同样方式运行的WebClient和其他客户端。

+0

完美 - 它的工作!非常感谢你。 – nickthompson 2012-04-19 06:47:16