首页 > 解决方案 > 在 IIS 上运行的 ASP.NET Web API 2 应用程序向 IIS express 上的本地应用程序返回 OK 数据,但在将请求应用程序部署到 IIS 后未经授权

问题描述

我有两个应用程序和一个数据库,一旦部署到不同服务器上的 IIS,我正试图访问所有“Play nice”。目标是让用户最初通过 Windows 进行身份验证,然后仍然让服务进行通信。我们希望用户 EID 作为每个步骤/请求的身份持久存在,但如果这是我们必须使用某种通用 AppPool 帐户的情况,我认为我们对此持开放态度。

当我从本地启动的应用程序从 IIS express 本地调用 Odata Web API 时,没有错误。该数据库是一个已经运行了一段时间的 MS SQL Server 数据库,包含一些应用程序使用的大量数据,并在使用 Telerik Fiddler 等查询时按预期返回数据给应用程序 1 。

应用程序和数据库都在不同的服务器上运行。

基本请求方案如下:

客户端设备(用户在此处针对 AD 进行身份验证)->GET->Application 2->GET->Application 1->SQLQUERY/DbContextRequest->SQL Server

因此,客户端设备发出获取请求(来自移动应用程序),该请求被发送到Application 2的 API 端点,然后调用Application 1 API 端点以从数据库中检索数据并返回到Application 2,其中在将数据发送回客户端设备之前,会进行少量数据组织。

细分:

应用一: ASP.NET Web API使用Odata控制器接收请求

应用 2:使用RestSharp发送请求的ASP.NET Web API 。

到目前为止,应用程序 1已经部署到其服务器数月,没有出现任何问题,但这是我们第一次尝试从另一个 Web 服务(应用程序 2 )调用应用程序 1

应用程序 2可以毫无问题地调用我们公司托管的其他 Web 服务,只有这个(应用程序 1)返回“未经授权”。

故障应用程序(应用程序 1)当前部署到 IIS。当我从在 IIS express 中运行应用程序 2 的本地应用程序机器向应用程序 1 发送 GET 请求时,数据按预期返回。在我的本地机器上使用 Fiddler 也可以毫无问题地从应用程序 1返回数据。

但是,一旦我将Application 2部署到 IIS,一旦部署到 IIS,带有 Odata 控制器(Application 1 )的应用程序就会对从Application 2发送到Application 1的任何请求返回“未经授权” 。

我使用log4Net并确定无论我是否使用模拟,我都是未经授权的,即使以同一用户(通过日志验证)或 AppPool 身份发送请求也是如此。我的 AD 帐户和 AppPool ID 帐户都可以完全访问返回“未授权”的应用程序 1的文件夹。

我正在使用RestSharp库发送请求:

    [HttpGet]
    [ResponseType(typeof(WorkOrderModel))]
    public IHttpActionResult GetWorkOrderDEBUG()
    {
        const string id = "1000";

        var client = new RestClient(Constants.ODATA_WEBSERVICEDOMAIN)
        {
            // Authentication needed when querying ODATA
            Authenticator = new NtlmAuthenticator()
        };
        var request = new RestRequest(Constants.ODATA_WEBSERVICE_PATH + "(" + id + ")", Method.GET);
        // add http header or request to remove odata metadata
        request.AddHeader("Accept", "application/json; odata.metadata=none");
        request.RequestFormat = DataFormat.Json;
        // Logging for debugging after deployment
        log.Debug("CURRENT IDENTITY: " + Environment.UserName);
        log.Debug("CURRENT OTHER IDENTITY: " + System.Security.Principal.WindowsIdentity.GetCurrent().Name);
        log.Debug("CURRENT MAYBE IDENTITY: " + GetUser());
        log.Debug("BaseUrl Path and Query: " + client.BaseUrl.PathAndQuery.ToString());
        log.Debug("Authenticator: " + client.Authenticator.ToString());
        log.Debug("Request Format: " + request.RequestFormat.ToString());
        log.Debug("Resource: " + request.Resource.ToString());

        // RestSharp execute request
        var response = client.Execute(request);

        // Logging for debugging after deployment
        if (response.ErrorMessage != null)
        {
            log.Debug("ErrorMessage: " + response.ErrorMessage.ToString());
        }

        if (response.ErrorException != null)
        {
            log.Debug("ErrorException.Message: " + response.ErrorException.Message.ToString());
            if (response.ErrorException.InnerException != null)
            {
                log.Debug("InnerException.Message: " + response.ErrorException.InnerException.Message.ToString());
            }
        }

        if (response.Content != null)
        {
            log.Debug("Content: " + response.Content.ToString());
        }

        log.Debug("ContentType: " + response.ContentType.ToString());
        //log.Debug("Headers: " + response.Headers.ToString());
        //log.Debug("Request: " + response.Request.ToString());
        log.Debug("ResponseStatus: " + response.ResponseStatus.ToString());
        log.Debug("ResponseURI-Path and Query: " + response.ResponseUri.PathAndQuery.ToString());
        log.Debug("ResponseURI-OriginalString: " + response.ResponseUri.OriginalString.ToString());
        log.Debug("ResponseURI-Segments: " + response.ResponseUri.Segments.ToString());
        log.Debug("Server: " + response.Server.ToString());
        log.Debug("Status Code: " + response.StatusCode.ToString());
        log.Debug("Status Description: " + response.StatusDescription.ToString());

        var content = response.Content;

        //if (content != null)
        //{
        //    log.Debug(content.ToString());
        //}

        var workOrder = JsonConvert.DeserializeObject<WorkOrderModel>(content);

        log.Debug(workOrder.ToString());

        return Ok(workOrder);
    }``

这是我的网络配置:

<system.web>
    <authentication mode="Windows" />
    <authorization>
      <allow users="*" /> 
      <deny users="?" />
    </authorization>
    <identity impersonate="true" />
    <customErrors mode="Off" />
    <compilation debug="true" targetFramework="4.6.1" />
    <httpRuntime targetFramework="4.6.1" />
    <httpModules>
      <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />
      <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" />
      <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" />
    </httpModules>
  </system.web>
  <system.webServer>
    <validation validateIntegratedModeConfiguration="false" />

我认为 webservice/server/controller/method 路径是可以的,因为它们在直接查询Application 1的 Odata Web API Controller 时工作正常,而它在我的本地机器上使用 Telerik Fiddler 或 SwaggerUI 在服务器/IIS 上运行,所以我不关心那里...

以下是一些错误日志:

    DEBUG 2019-11-15 17:00:56,786 1397487ms 
                                          Controller  GetWorkOrder       - CURRENT IDENTITY: myid123
    DEBUG 2019-11-15 17:00:56,786 1397487ms Controller  GetWorkOrder       - CURRENT OTHER IDENTITY: MBULOGIN\myid123
    DEBUG 2019-11-15 17:00:56,786 1397487ms Controller  GetWorkOrder       - BaseUrl Path and Query: /app/odata/
    DEBUG 2019-11-15 17:00:56,786 1397487ms Controller  GetWorkOrder       - Authenticator: RestSharp.Authenticators.NtlmAuthenticator
    DEBUG 2019-11-15 17:00:56,786 1397487ms Controller  GetWorkOrder       - Default Parameters:System.Collections.Generic.List`1[RestSharp.Parameter]
    DEBUG 2019-11-15 17:00:56,786 1397487ms Controller  GetWorkOrder       - Parameters: System.Collections.Generic.List`1[RestSharp.Parameter]
    DEBUG 2019-11-15 17:00:56,786 1397487ms Controller  GetWorkOrder       - Request Format: Json
    DEBUG 2019-11-15 17:00:56,786 1397487ms Controller  GetWorkOrder       - Resource: WorkOrders(100000)
    DEBUG 2019-11-15 17:00:56,802 1397503ms Controller  GetWorkOrder       - Content: <!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>

    DEBUG 2019-11-15 17:00:56,802 1397503ms Controller  GetWorkOrder       - ContentType: text/html
    DEBUG 2019-11-15 17:00:56,802 1397503ms Controller  GetWorkOrder       - Headers: System.Collections.Generic.List`1[RestSharp.Parameter]
    DEBUG 2019-11-15 17:00:56,802 1397503ms Controller  GetWorkOrder       - Request: RestSharp.RestRequest
    DEBUG 2019-11-15 17:00:56,802 1397503ms Controller  GetWorkOrder       - ResponseStatus: Completed
    DEBUG 2019-11-15 17:00:56,802 1397503ms Controller  GetWorkOrder       - ResponseURI-Path and Query: /app/odata/WorkOrders(1000000)
    DEBUG 2019-11-15 17:00:56,802 1397503ms Controller  GetWorkOrder       - ResponseURI-OriginalString: https://example.com/app/odata/WorkOrders(1000000)
    DEBUG 2019-11-15 17:00:56,802 1397503ms Controller  GetWorkOrder       - ResponseURI-Segments: System.String[]
    DEBUG 2019-11-15 17:00:56,802 1397503ms Controller  GetWorkOrder       - Server: Microsoft-IIS/8.5
    DEBUG 2019-11-15 17:00:56,802 1397503ms Controller  GetWorkOrder       - Status Code: Unauthorized
    DEBUG 2019-11-15 17:00:56,802 1397503ms Controller  GetWorkOrder       - Status Description: Unauthorized

在不模拟发送 GET 请求时,来自 log4net 的错误日志与上述相同,只是身份更改为 AppPool 的身份。

我不明白从 IIS 到Application 1的 Odata Web Api 控制器的请求与从我在 IIS express 中运行该应用程序的机器本地发出的请求相比有什么不同,在使用模拟之后更是如此。一旦被模拟,在本地运行没有问题的同一帐户是“未经授权的”。

我在 IIS GUI 中检查了应用程序的授权策略,两个 IIS 实例都允许 Windows Auth。

这是服务器/IIS 设置吗?如果是这样,适用于哪个应用程序?我真的不确定还有什么要调查的,与我的本地计算机相比,似乎有某种信息与来自应用程序 2的 GET 请求一起发送,当它来自 IIS 时,触发请求未被授权。 ..但它可能是什么?

标签: asp.netiisasp.net-web-api2asp.net-authorizationasp.net-authentication

解决方案


推荐阅读