添加凭据标头时的ASP.NET Web API 401

kil*_*foe 4 c# asp.net authentication asp.net-web-api

这类似于这个问题 ; 但是,略有不同,答案对我不起作用(或者看起来像是原始的提问者)

我在.NET Framework 4.5中创建了一个ASP.NET Web API项目。我想添加基本身份验证,在该身份验证中,我会在每次请求时验证用户凭据。我使用从几个站点找到的代码(我会发布链接,但是我需要更多信誉才能发布两个以上的链接)来创建BasicAuthenticationAttribute并提出一个可行的解决方案。

所有这些在localhost上都运行良好,但是当我将其移至GoDaddy共享托管站点时,它始终会返回未经授权的状态。此未经授权的响应出现在我的授权之前,我已经通过删除授权码证明了这一点,这仍然会导致未经授权的响应。现在,有趣的是,如果我没有在请求中添加用户凭据,它就可以正常工作。仅当我添加凭据时,才会收到未经授权的响应。

总结一下...

  • 没有凭证标头的localhost:有效
  • 具有凭据头的localhost:有效
  • 没有凭证标头的GoDaddy:有效
  • 具有凭证标头的GoDaddy:未经授权

我已经看到了几篇概述表单身份验证的文章,我需要启用匿名身份验证。我已经尝试了所有方法,但没有任何方法可以解决问题。我还尝试过删除web.config中的FormsAuthentication,方法是首先删除将其添加的代码,并告诉它删除此处所示的表单身份验证。

web.config的相关部分(我已经注释掉了身份验证部分,对它进行了注释和注释,结果相同):

<!--<authentication mode="Forms">
</authentication>-->

<membership defaultProvider="AspNetSqlMembershipProvider" userIsOnlineTimeWindow="30">
  <providers>
    <clear/>
    <add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" connectionStringName="MyConnectionString" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" applicationName="MyApplicationName" requiresUniqueEmail="false" passwordFormat="Hashed" maxInvalidPasswordAttempts="5" passwordAttemptWindow="10" passwordStrengthRegularExpression="" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0"/>
  </providers>
</membership>

<roleManager enabled="true" defaultProvider="CustomizedRoleProvider" cookieTimeout="30">
  <providers>
    <add name="CustomizedRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="MyConnectionString" applicationName="MyApplicationName"/>
  </providers>
</roleManager>

<system.webServer>
  <validation validateIntegratedModeConfiguration="false" />
  <modules runAllManagedModulesForAllRequests="true">
    <remove name="FormsAuthentication" />
  </modules>
</system.webServer>
Run Code Online (Sandbox Code Playgroud)

客户代码调用服务:

using (var client = new HttpClient())
{
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

    string credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes("MyUserName" + ":" + "MyPassword"));
    client.DefaultRequestHeaders.Authorization = System.Net.Http.Headers.AuthenticationHeaderValue.Parse("Basic " + credentials);

    var obj = new MyObject()
    {
        MyData...
    };

    HttpResponseMessage response = await client.PostAsXmlAsync("<URI>", obj);
...
}
Run Code Online (Sandbox Code Playgroud)

未经授权的请求:

POST <URI> HTTP/1.1
Accept: application/json
Authorization: Basic <encoded info>
Content-Type: application/xml; charset=utf-8
Host: <host>
Content-Length: 705
Expect: 100-continue
Connection: Keep-Alive

<data>
Run Code Online (Sandbox Code Playgroud)

未经授权的回应:

HTTP/1.1 401 Unauthorized
Content-Type: text/html
Server: Microsoft-IIS/7.0
WWW-Authenticate: Basic realm="<host>"
X-Powered-By: ASP.NET
Date: Tue, 11 Feb 2014 00:52:10 GMT
Content-Length: 1293

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"/>
<title>401 - Unauthorized: Access is denied due to invalid credentials.</title>
<style type="text/css">
<!--
body{margin:0;font-size:.7em;font-family:Verdana, Arial, Helvetica, sans-serif;background:#EEEEEE;}
fieldset{padding:0 15px 10px 15px;} 
h1{font-size:2.4em;margin:0;color:#FFF;}
h2{font-size:1.7em;margin:0;color:#CC0000;} 
h3{font-size:1.2em;margin:10px 0 0 0;color:#000000;} 
#header{width:96%;margin:0 0 0 0;padding:6px 2% 6px 2%;font-family:"trebuchet MS", Verdana, sans-serif;color:#FFF;
background-color:#555555;}
#content{margin:0 0 0 2%;position:relative;}
.content-container{background:#FFF;width:96%;margin-top:8px;padding:10px;position:relative;}
-->
</style>
</head>
<body>
<div id="header"><h1>Server Error</h1></div>
<div id="content">
 <div class="content-container"><fieldset>
  <h2>401 - Unauthorized: Access is denied due to invalid credentials.</h2>
  <h3>You do not have permission to view this directory or page using the credentials that you supplied.</h3>
 </fieldset></div>
</div>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

ram*_*cob 5

经过搜索和测试,我终于找到了问题所在。

在GoDaddy的共享托管环境中,将在所有IIS应用程序上自动且永久启用基本身份验证。您可以选择在GoDaddy的IIS管理Web门户中选中一个复选框以启用“匿名”。如果这样做,则等同于在“身份验证”图标下的IIS中同时启用了“基本”和“匿名”。

这很容易在本地IIS中重新创建。对我来说,问题是在本地计算机上,我没有安装基本身份验证功能,因此甚至无法选择。安装并启用它后,我得到了从GoDaddy获得的确切症状。

由于此方案中的IIS被配置为查找基本身份验证,因此它会在您的请求中看到Authorization标头,并尝试执行工作而不是将其传递给您的代码。这是有道理的,但不是所需的行为。

只能通过在IIS应用程序上禁用基本身份验证来实现所需的行为。这就是GoDaddy的共享托管的麻烦所在-他们不会或无法禁用基本身份验证。 我得到的答案是,如果我想要这种级别的控制,则需要专用的托管环境

解决方法(编辑)

如果您遵循以下标准,请停止阅读:-)。如果将Authorization标头的方案部分更改为Basic以外的其他内容,则IIS将忽略该标头并将其继续传递!这意味着您可以更改为以下内容:

Authorization: Pickle cmFtc2V5amFjb2I6aXNfYV9yYWRfZHVkZQ==

然后只需更改您的代码以查找Pickle,它就可以工作(在我的测试中对我有用)。吃了,GoDaddy!