【问题标题】:ASP.NET Web API 401 when adding credential header添加凭据标头时的 ASP.NET Web API 401
【发布时间】:2014-03-08 14:30:38
【问题描述】:

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

我有一个在 .NET Framework 4.5 中创建的 asp.net web api 项目。我想添加基本身份验证,在每个请求中我都会验证用户凭据。我使用从几个站点找到的代码(我会发布链接,但我需要更多的声誉才能发布超过 2 个链接)来创建 BasicAuthenticationAttribute 并提出一个可行的解决方案。

这一切在 localhost 上运行良好,但是当我将它移到我们的 GoDaddy 共享托管站点时,它总是返回未经授权的。这个未经授权的响应出现在我的授权之前,我已经通过删除我的授权码证明了这一点,这仍然会导致未经授权的响应。现在,有趣的是,如果我不在请求中添加用户凭据,它可以正常工作。只有当我添加凭据时,我才会收到未经授权的响应。

总结一下……

  • 没有凭证头的本地主机:有效
  • 带有凭据标头的本地主机:工作
  • 没有凭据标头的 GoDaddy:有效
  • 带有凭据标头的 GoDaddy:未经授权

我看到一些帖子概述了表单身份验证可能会妨碍我,我需要启用匿名身份验证。所有这些我都试过了,但没有解决这个问题。我还尝试删除 web.config 中的 FormsAuthentication,方法是首先删除添加它的代码,并告诉它删除表单身份验证,如 here 所述。

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>

调用服务的客户端代码:

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);
...
}

未经授权的请求:

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>

未经授权的回复:

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>

【问题讨论】:

  • 试试&lt;authentication mode="None"&gt; == "app会处理它"
  • 我也试过这个 - 只是为了安全起见再次尝试 - 但我得到了相同的结果。
  • 有什么想法吗?我今天在电话上花了 2.5 个小时与 GoDaddy 试图解决这个问题,但他们正试图放弃它。
  • 假设您已经完全检查/调试了您的ActionFilter(它正在被调用,凭据已正确发送和验证等),它似乎指向一个 IIS 设置。您是否有裸机和/或 IIS 管理器访问权限(例如,查看 IIS -> 身份验证设置)?
  • 如果没有凭证头,我的 ActionFilter 会被调用。如果我添加凭据标头,它只会到达 global.asax Application_BeginRequest,而不是 ActionFilter。我删除了我只是为了确保它没有对任何人进行身份验证的 ActionFilter。我在 Application_BeginRequest 中添加了一些代码来记录当前的身份验证模式,它正在记录“无”。我登录了:(ConfigurationManager.GetSection("system.web/authentication") as AuthenticationSection).Mode.ToString()

标签: c# asp.net authentication asp.net-web-api


【解决方案1】:

我从未发现问题并需要解决方案,因此我不得不更改客户端发送的对象以包含用户名和用于识别它们的 guid,并且没有任何授权标头。这是一个有趣的解决方法。您在 iis 中写的有关基本授权的信息有助于我们转向专用并遇到同样的问题,谢谢!

【讨论】:

  • Pickle 的使用有点半开玩笑 :-) “真正的”Web API(Box、SalesForce 等)使用 Authorization 标头并将方案设置为“Token”,这样可能更合法一些。哦,只是为了让我不要忘记:总是通过 SSL 执行此操作! /免责声明
【解决方案2】:

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

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

这很容易在本地 IIS 中重新创建。对我来说,问题是在我的本地机器上,我没有安装基本身份验证功能,所以它甚至不是一个选项。安装并启用它后,我得到了从 GoDaddy 得到的确切症状。

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

只有在 IIS 应用程序上禁用基本身份验证才能实现所需的行为。这就是 GoDaddy 的共享主机变得痛苦的地方——他们不会或不能禁用基本身份验证。 我得到的答案是,如果我想要这种级别的控制,我需要一个专用的托管环境

解决方法(编辑)

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

Authorization: Pickle cmFtc2V5amFjb2I6aXNfYV9yYWRfZHVkZQ==

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

【讨论】:

  • 您为我节省了无数小时的调试时间。非常感谢!
  • 我只花了将近一周的时间来寻找那个问题。我正在考虑这个问题,但我不知道如何调试这个问题。你的建议终于解决了!!谢谢!
猜你喜欢
  • 2019-03-04
  • 1970-01-01
  • 2011-02-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-21
  • 1970-01-01
相关资源
最近更新 更多