无法使用基本身份验证进行身份验证

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了无法使用基本身份验证进行身份验证相关的知识,希望对你有一定的参考价值。

我有一个ASP.NET WebApi服务,需要http基本身份验证(这是为了演示,而不是生产,所以这是基本身份验证的原因,而不是更安全的东西)。 Visual Studio IIS Express服务器运行良好,并通过自定义HTTP模块进行身份验证。

当我将站点部署到托管服务器时,它会失败并继续弹出登录屏幕。我向Fiddler验证了请求正在发送并且正在发送凭据。但它继续响应401未经授权的响应。似乎请求凭据在从客户端到服务器的时间内以某种方式丢失。我花了很多时间来尝试诊断这一点,使用Web API和IIS进行.NET身份验证似乎非常混乱。请帮忙!!

来自Fiddler的传出请求显示:

获取mywebsiteaddress HTTP / 1.1 主持人:我的网站地址 User-Agent:Mozilla / 5.0(Windows NT 6.1; WOW64; rv:21.0)Gecko / 20100101 Firefox / 21.0 接受:/ Accept-Language:en-US,en; q = 0.5 Accept-Encoding:gzip,deflate 授权:基本YmJvbm5ldDE4Om9jdG9iZXIxNw == X-Requested-With:XMLHttpRequest 推荐人:狡猾 连接:保持活力

以下是我的配置的相关部分(如果需要,我可以发布更多):

<modules>
  <add name="BasicAuthHttpModule" type="ITMService.Modules.BasicAuthHttpModule"/>
</modules>

<httpModules>
  <add name="BasicAuthHttpModule" type="ITMService.Modules.BasicAuthHttpModule"/>
</httpModules>

<authentication mode="Windows"/>

我的自定义http模块(在visual studio的测试中工作正常)。这主要取自example on asp.net

namespace ITMService.Modules
{
public class BasicAuthHttpModule : IHttpModule
{

    private const string Realm = "www.mysite.net";

    public void Init(HttpApplication context)
    {
        context.AuthenticateRequest += OnApplicationAuthenticateRequest;
        context.EndRequest += OnApplicationEndRequest;

    }

    private static void SetPrincipal(IPrincipal principal)
    {
        Thread.CurrentPrincipal = principal;
        if (HttpContext.Current != null)
        {
            HttpContext.Current.User = principal;
            Log.LogIt("current principal: " + principal.Identity.Name);
        }
    }


    private static bool CheckPassword(string username, string password)
    {
        string passHash = AuthUser.GetUserPassword(username);
        if (PasswordHash.ValidatePassword(password, passHash))
        {
            return true;
        }
        else
        {
            return false;
        }

    }

    private static bool AuthenticateUser(string credentials)
    {
        bool validated = false;

        try
        {
            var encoding = Encoding.GetEncoding("iso-8859-1");
            credentials = encoding.GetString(Convert.FromBase64String(credentials));

            int separator = credentials.IndexOf(':');
            string name = credentials.Substring(0, separator);
            string password = credentials.Substring(separator + 1);

            validated = CheckPassword(name, password);

            if (validated)
            {
                var identity = new GenericIdentity(name);
                SetPrincipal(new GenericPrincipal(identity, null));
            }
        }
        catch (FormatException)
        {
            // Credentials were not formatted correctly.
            validated = false;
            Log.LogIt("not validated");

        }
        return validated;
    }

    private static void OnApplicationAuthenticateRequest(object sender, EventArgs e)
    {

        var request = HttpContext.Current.Request;
        var authHeader = request.Headers["Authorization"];
        if (authHeader != null)
        {

            var authHeaderVal = AuthenticationHeaderValue.Parse(authHeader);

            // RFC 2617 sec 1.2, "scheme" name is case-insensitive
            if (authHeaderVal.Scheme.Equals("basic",
                    StringComparison.OrdinalIgnoreCase) &&
                authHeaderVal.Parameter != null)
            {

                AuthenticateUser(authHeaderVal.Parameter);
            }
        }
    }

    // If the request was unauthorized, add the WWW-Authenticate header 
    // to the response.
    private static void OnApplicationEndRequest(object sender, EventArgs e)
    {

        var response = HttpContext.Current.Response;
        if (response.StatusCode == 401)
        {
            response.Headers.Add("WWW-Authenticate",
                string.Format("Basic realm="{0}"", Realm));
        }
    }

    public void Dispose()
    {
    }
}
}

我的IIS服务器以集成管道模式托管并运行.NET 4。我禁用了表单身份验证和禁用模拟。我在服务器上启用了基本身份验证和匿名身份验证方法。

我已经阅读了无数的论坛回复和关于此的帖子,没有什么能让我得到一个明确的答案。

答案

我看到两个www-Authenticate响应头。我相信您的HTTP模块正在添加一个,而IIS正在添加一个。确保在IIS中禁用所有类型的身份验证,如此。我的猜测是你在IIS中启用了基本身份验证。

另一答案

只是为了完整性:

BasicAuthentication的大多数示例都描述了在IIS应用程序配置中启用“Windows身份验证”。这在许多情况下都有效(例如,连接到站点的浏览器),但不适用于使用网络凭据的dotNet客户端。为什么?

通过fiddler简要介绍一下http header:

WWW-Authenticate: Basic realm="My Realm"
WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM

浏览器正在选择BasicAuthentication。但是dotClient正在启动协商(Kerberos)或NTLM身份验证。

案例1:如果您的服务器位于同一个域中并且您正在使用正常的登录凭据=>一切正常,服务器正在为您进行协商

案例2:如果您的webapp正在提供自己的BasicAuthenticationModule进行身份验证(例如,拥有自己的用户数据库),则身份验证将失败。

案例2的解决方案:在iis或system.webServer-security中禁用Windows身份验证,以便仅向客户端提供BasicAuthentication。然后,您可以使用网络凭据连接到应用程序,而无需手动设置AuthenticationHeader或操作身份验证缓存。

另一答案

今天还有另一个question沿着同样的路线。解决此问题的第一步是通过删除Web.config中的<authentication mode="Windows"/>来禁用Windows身份验证。另外,响应消息是什么样的? WWW-Authenticate回来了什么?

以上是关于无法使用基本身份验证进行身份验证的主要内容,如果未能解决你的问题,请参考以下文章

无法使用 WCF 调用具有基本身份验证的 Web 服务

如何使用jQuery和Ajax对DreamFactory进行基本身份验证

使用 jQuery 和 Ajax 进行基本身份验证

使用 fetch 进行基本身份验证(或任何身份验证)

Silverlight 浏览器的基本身份验证

当我们有一个身份验证系统时,如何为某些链接添加基本身份验证