2

我有一个 OData WCF 服务的工作实现,现在需要使用基本的自定义身份验证在 IIS 中发布。

实现基于Microsoft OData 示例,并且在 IIS Express 下运行良好。当我将其发布到仅启用基本身份验证的 IIS 7.5 时,仅在初始请求时调用 AuthenticateRequest 处理程序,它返回状态代码 401 并要求进行身份验证。

后续请求不再调用 AuthenticateRequest。在IIS上调试服务时,肯定会调用BeginRequest,只是管道中不存在AuthenticateRequest?IIS Express 中的每个请求都会调用两者。

IIS 身份验证配置:

IIS 身份验证配置

IHttpModule 代码:

public class BasicAuthModule: IHttpModule
{
    // based on http://msdn.microsoft.com/en-gb/data/gg192997.aspx

    public void Init(HttpApplication app)
    {
        app.AuthenticateRequest += AuthenticateRequest;
        app.BeginRequest += BeginRequest;
    }

    private void BeginRequest(object sender, EventArgs e)
    {
        var app = (HttpApplication)sender;
        if(app.Context == null)
        {
            throw new Exception("Will not happen");
        }
    }

    private void AuthenticateRequest(object sender, EventArgs e)
    {
        var app = (HttpApplication)sender;
        if(!app.Request.Headers.AllKeys.Contains("Authorization"))
        {
            CreateNotAuthorizedResponse(app, 401, 1, "Please provide Authorization headers with your request.");
            app.CompleteRequest();
        }
        else if(!BasicAuthProvider.Authenticate(app.Context))
        {
            CreateNotAuthorizedResponse(app, 401, 1, "Logon failed.");
            app.CompleteRequest();
        }
    }

    private static void CreateNotAuthorizedResponse(HttpApplication app, int code, int subCode, string description)
    {
        var response = app.Context.Response;
//      response.Status = "401 Unauthorized";
        response.StatusCode = code;
        response.SubStatusCode = subCode;
        response.StatusDescription = description;
//      response.AppendHeader("WWW-Authenticate", "Basic");
//      response.End();
    }

    public void Dispose()
    {
    }
}

网络配置:

<?xml version="1.0"?>
<configuration>
  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5"/>
  </system.web>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <protocolMapping>
        <add binding="basicHttpsBinding" scheme="https" />
    </protocolMapping>    
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>
      <modules runAllManagedModulesForAllRequests="true">
          <add name="BasicAuthModule" type="WcfTestService.BasicAuthModule"/>
      </modules>
    <directoryBrowse enabled="true"/>
  </system.webServer>
</configuration>

还有一个问题:为什么身份验证在 Visual Studio 2012 调试服务器中有效,但在 IIS 7.5 中无效?完整的测试项目可以从这里下载。

编辑:

我在 CreateNotAuthorizedResponse 函数和 response.End() 中注释掉了导致异常的过多测试代码(我在发布前的最后一分钟添加了它)。

在检查请求时,除了 Cookie 可能由于某种原因导致 IIS 跳过身份验证之外,一切似乎都应该正常工作。在前 2 个原始请求 - 回复对下方:

请求 1:

GET http://localhost:8080/test/ HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8,pl;q=0.6
Cookie: ASPSESSIONIDAQRDDBTR=BPCFKGDDCGJLPFKHEPOLPMFK; __RequestVerificationToken_L2RlbGl2ZXJ50=j0o-RDC12Z_E1o1nnXU_9iFaThUEPXRXDNKepqoX2fmgjg8gRB6Hi9fs3MSGxUvYQs6tJ0Jxsf6U20WKWpOrj4azgL_VpVzQHcNyJghUrKg1; __RequestVerificationToken=uOeCVgZDguOs3mRA7O4nhj88wJ_mFR6t1QN7vl7mOPGaNBoEnVFmIQVoUwxim8NbODJKMz5fBuAoPKo7Ek-4JeujsOIyIxjRB1xS_JaFF381; .ASPXAUTH=C2965A60E4BB162123A2CDDA8FD825C9DF3625116E5722C9B873BA64F041CCDCAB098EA3A208C2061D8D5746BC0832413105BA274C1B37DB8276471D49DE12562E4E93933289828427F559057519E75421493909E215EAA0DFB4C8DBE213EAC19AB6025EA715658A8D57CAFA308F7AC4A9051687777D2E82B7A2552917466E7C0BFA0C23EEE272F7E83C3718371375358B1199F155FB882EF8F5082CB28F6E030146DE365B5E4D8FE25E55EDD3F03788

回复 1:(由 CreateNotAuthorizedResponse 方法创建)

HTTP/1.1 401 Please provide Authorization headers with your request.
Cache-Control: private
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/7.5
WWW-Authenticate: Basic realm="localhost"
X-Powered-By: ASP.NET
Date: Mon, 20 Oct 2014 13:03:14 GMT
Content-Length: 6607

<!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> 
<title>IIS 7.5 Detailed Error - 401.1 - Please provide Authorization headers with your request.</title> 

请求 2(当输入 test:test - dGVzdDp0ZXN0):

GET http://localhost:8080/test/ HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Authorization: Basic dGVzdDp0ZXN0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8,pl;q=0.6
Cookie: ASPSESSIONIDAQRDDBTR=BPCFKGDDCGJLPFKHEPOLPMFK; __RequestVerificationToken_L2RlbGl2ZXJ50=j0o-RDC12Z_E1o1nnXU_9iFaThUEPXRXDNKepqoX2fmgjg8gRB6Hi9fs3MSGxUvYQs6tJ0Jxsf6U20WKWpOrj4azgL_VpVzQHcNyJghUrKg1; __RequestVerificationToken=uOeCVgZDguOs3mRA7O4nhj88wJ_mFR6t1QN7vl7mOPGaNBoEnVFmIQVoUwxim8NbODJKMz5fBuAoPKo7Ek-4JeujsOIyIxjRB1xS_JaFF381; .ASPXAUTH=C2965A60E4BB162123A2CDDA8FD825C9DF3625116E5722C9B873BA64F041CCDCAB098EA3A208C2061D8D5746BC0832413105BA274C1B37DB8276471D49DE12562E4E93933289828427F559057519E75421493909E215EAA0DFB4C8DBE213EAC19AB6025EA715658A8D57CAFA308F7AC4A9051687777D2E82B7A2552917466E7C0BFA0C23EEE272F7E83C3718371375358B1199F155FB882EF8F5082CB28F6E030146DE365B5E4D8FE25E55EDD3F03788

响应 2(调用了 BeginRequest 但未调用 AuthenticateRequest):

HTTP/1.1 401 Unauthorized
Cache-Control: private
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/7.5
WWW-Authenticate: Basic realm="localhost"
X-Powered-By: ASP.NET
Date: Mon, 20 Oct 2014 13:03:17 GMT
Content-Length: 6531

<!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> 
<title>IIS 7.5 Detailed Error - 401.1 - Unauthorized</title> 
4

1 回答 1

1

I think you are mixing up IIS built-in basic authentication with your own custom authentication module. The short answer is to disable Basic Authentication in IIS and enable Anonymous. This will pass all the auth work onto asp.net.

If your are testing in VS I'm assuming you are doing so via a browser that is auto launched when you hit F5.

With basic auth turned on IIS initially responds with a 401 which causes the browser to display the login form.

The credentials you enter there have to be valid windows credentials, which IIS validates against your windows accounts. Once IIS has validated these credentials it will pass the request along to your code.

If you enter valid windows credentials the event is raised but your code will reject it because the credentials are not test/test and return a 401.1

If you enter test/test then IIS is rejecting the credentials and sends back a 401 so your event is never called.

Final word: You should be testing your web service using an http client (e.g. unit test with System.Net.WebClient), or use a chrome plugin (postman/devhttp) to test at the http level. If you are already doing this then forgive my assumption.

于 2014-10-22T17:18:20.737 回答