gpt4 book ai didi

asp.net-web-api - OAuthBearerAuthenticationMiddleware - 服务器无法在发送 HTTP header 后附加 header

转载 作者:行者123 更新时间:2023-12-02 20:10:02 25 4
gpt4 key购买 nike

我一直在尝试将一些 OWIN 中间件插入现有的 WebApi 项目中。我的初创公司最初只包含以下几行:

application.UseOAuthBearerAuthentication(newOAuthBearerAuthenticationOptions());
application.UseWebApi(config);

使用此配置,我间歇性地(主要是在 iisreset 之后)收到格式错误的响应(由 fiddler 识别),这些响应是由中间件尝试添加 header 引起的,但在发送响应后,这被报告为异常(exception):

Server cannot append header after HTTP headers have been sent.

我重新编译了 Microsoft.Owin.Security.OAuth 以添加一些额外的跟踪来显示事情发生的顺序,并得到以下输出:

Microsoft.Owin.Security.OAuth.OAuthBearerAuthenticationMiddleware Information: 0 : : OAUTH: Authenticating...
System.Web.Http.Request: ;;http://localhost:555/entityinstance/member
System.Web.Http.Controllers: WebHostHttpControllerTypeResolver;GetControllerTypes;:
System.Web.Http.Controllers: WebHostHttpControllerTypeResolver;GetControllerTypes;:
System.Web.Http.MessageHandlers: LogHandler;SendAsync;:
System.Web.Http.Controllers: DefaultHttpControllerSelector;SelectController;Route='entityDefinitionName:member,controller:EntityInstance'
System.Web.Http.Controllers: DefaultHttpControllerSelector;SelectController;EntityInstance
System.Web.Http.Controllers: HttpControllerDescriptor;CreateController;:
System.Web.Http.Controllers: WindsorCompositionRoot;Create;:
System.Web.Http.Controllers: WindsorCompositionRoot;Create;Loyalty.Services.WebApi.Controllers.EntityInstanceController
System.Web.Http.Controllers: HttpControllerDescriptor;CreateController;Loyalty.Services.WebApi.Controllers.EntityInstanceController
System.Web.Http.Controllers: EntityInstanceController;ExecuteAsync;:
System.Web.Http.Action: ApiControllerActionSelector;SelectAction;:
System.Web.Http.Action: ApiControllerActionSelector;SelectAction;Selected action 'Get(String entityDefinitionName)'
System.Net.Http.Formatting: DefaultContentNegotiator;Negotiate;Type='HttpError', formatters=[JsonMediaTypeFormatterTracer, XmlMediaTypeFormatterTracer, FormUrlEncodedMediaTypeFormatterTracer, FormUrlEncodedMediaTypeFormatterTracer]
System.Net.Http.Formatting: JsonMediaTypeFormatter;GetPerRequestFormatterInstance;Obtaining formatter of type 'JsonMediaTypeFormatter' for type='HttpError', mediaType='application/json; charset=utf-8'
System.Net.Http.Formatting: JsonMediaTypeFormatter;GetPerRequestFormatterInstance;Will use same 'JsonMediaTypeFormatter' formatter
System.Net.Http.Formatting: DefaultContentNegotiator;Negotiate;Selected formatter='JsonMediaTypeFormatter', content-type='application/json; charset=utf-8'
System.Web.Http.Controllers: EntityInstanceController;ExecuteAsync;:
System.Net.Http.Formatting: JsonMediaTypeFormatter;WriteToStreamAsync;Value='System.Web.Http.HttpError', type='HttpError', content-type='application/json; charset=utf-8'
System.Net.Http.Formatting: JsonMediaTypeFormatter;WriteToStreamAsync;:
System.Web.Http.Request: ;;Content-type='application/json; charset=utf-8', content-length=68
System.Web.Http.Controllers: EntityInstanceController;Dispose;:
System.Web.Http.Controllers: EntityInstanceController;Dispose;:
Microsoft.Owin.Security.OAuth.OAuthBearerAuthenticationMiddleware Information: 0 : : OAUTH: Applying Challange...
A first chance exception of type 'System.Web.HttpException' occurred in System.Web.dll

所以看起来中间件的响应处理部分遵循俄罗斯套娃模型,正在尝试修改 header ,但响应已经在前一阶段完成了。我尝试添加不同的阶段标记来控制此行为,但似乎没有任何帮助。

看到该痕迹后令人惊讶的是,它并不是一直在发生。我用一个更小的实现编写了我自己的这个中间件版本,在注册这个中间件之后,代替 MS 的中间件,我确实开始在每个请求上看到错误,我想知道它是否总是被抛出,但被吞没有时或者 fiddler 是否没有等待足够长的时间来看到它。

我目前的最佳猜测是,此问题是由于对 Owin 使用与 WebApi 设置不同的 HttpConfiguration 造成的。不幸的是,我无法交换整个 HTTPApplication 并转到 OWIN 锁定库,因为委托(delegate)处理程序在 OWIN 的不同上下文中运行,您无权访问路由数据,因为这会破坏我们现有的很多基础设施。

任何人都可以给我任何关于这里发生的事情的指示吗?这是受支持的场景吗?我是否遗漏了一些明显的东西?

最佳答案

好吧,我已经解决了!

简答

如果您使用两个 HttpConfiguration 实例,则会出现此问题。您必须确保对 application.UseWebApi(config); 的调用和 webapi 配置使用相同的 HttpConfiguration。

我猜测这样做的原因是,除非您使用相同的配置,否则运行时无法知道响应何时准备好发送,因为没有一个地方可以确定如果您的所有处理程序都已运行。

中等大小的答案

转换现有 WebAPI 应用程序时,您通常会在 global.asax application_start 处理程序中注册容器 Bootstrap 和 Web API 配置。迁移到 OWIN 时,您要做的第一件事就是添加一个 Startup 类,用于通过 appbuilder 配置 OWIN 应用程序。在这种情况下,很容易遵循纯 OWIN 示例并在 startup 中新建一个新的 HttpConfiguration,同时利用 GlobalConfiguration 保留现有注册。你最终会得到类似的结果:

全局.asax:

    protected void Application_Start()
{
var config = GlobalConfiguration.Configuration;
Bootstrapper.Run(config);
WebApiConfig.Register(config);
}

启动.cs:

  public void Configuration(IAppBuilder application)
{
var config = new HttpConfiguration();
application.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions());
application.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());

config.MapHttpAttributeRoutes();
application.UseWebApi(config);
}

当你真正需要的是:

public void Configuration(IAppBuilder application)
{
var config = new HttpConfiguration();

Bootstrapper.Run(config);

application.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions());
application.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());

WebApiConfig.Register(config);
config.MapHttpAttributeRoutes();
application.UseWebApi(config);
}

更长的答案

您可能会认为这是相当明显的,如果您仔细遵循这些示例,您很快就会明白这一点,而且您是对的。这是我在遇到问题后不久尝试过的事情(我没有编写原始代码;))。不幸的是,如果您尝试使用 WebApi 项目中使用的一些标准 web.config 进行上述操作,您将遇到许多其他问题,这些问题会带来您认为可能与原始问题相关的问题,但事实并非如此。

问题:每个请求都出现 404。

解决方案:您需要注册以下处理程序:

 <!-- language: lang-xml -->
<handlers accessPolicy="Read, Execute, Script">
<remove name="WebDAV" />
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="TRACEVerbHandler" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*" verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>

问题:发送响应后无法重定向/发出 401 后,404 重定向到 login.aspx

解决方案:您需要取消注册 formsAuthentication 模块:

<!-- language: lang-xml -->
<modules runAllManagedModulesForAllRequests="true">
<remove name="FormsAuthentication" />
</modules>

问题: "message": "未找到与请求 URI ' http://blah ' 匹配的 HTTP 资源。", "messageDetail": "未找到与名为“blah”的 Controller 匹配的类型。"

解决方案:这是一个微妙的解决方案。我们使用委托(delegate)处理程序来扫描 Controller 操作中的 Authenticate 属性。我们使用以下代码来完成此操作:

public virtual T ScanForAttribute<T>(HttpRequestMessage request, HttpConfiguration config) where T : Attribute
{
var controllerSelector = new DefaultHttpControllerSelector(config);
var descriptor = controllerSelector.SelectController(request);

.. some other stuff
}

现在,我们在 OWIN 下遇到的问题是 controllerSelector.SelectController(在 System.Web.Http 中实现)内部依赖于 MS_RequestContext > request 属性,如果没有找到它,则会抛出状态码为 404 的 HttpResponseException,这会导致发送 404 响应,从而出现上述问题。您可以通过一些技巧在 OWIN 中实现此功能:

public virtual T ScanForAttribute<T>(HttpRequestMessage request, HttpConfiguration config) where T : Attribute
{
var data = request.GetConfiguration().Routes.GetRouteData(request);
((HttpRequestContext) request.Properties["MS_RequestContext"]).RouteData = data;

var controllerSelector = new DefaultHttpControllerSelector(config);
var descriptor = controllerSelector.SelectController(request);
.. Some other stuff
}

问题:您尝试使用以下方式解析调用者 IP:

if (request.Properties.ContainsKey("MS_HttpContext"))
{
return ((HttpContextWrapper)request.Properties["MS_HttpContext"]).Request.UserHostAddress;
}

解决方案:您还需要检查以下内容,以使其在 OWIN 下工作:

  if (request.Properties.ContainsKey("MS_OwinContext"))
{
OwinContext owinContext = (OwinContext)request.Properties["MS_OwinContext"];
if (owinContext != null)
{
return owinContext.Request.RemoteIpAddress;
}
}

而且......我们现在工作得很好!如果 OWIN 有更多的跟踪输出,解决这个问题会容易得多,但不幸的是,katana 项目中的许多中间件在跟踪方面有点安静,希望随着时间的推移,这个问题将得到解决!

希望这有帮助。

关于asp.net-web-api - OAuthBearerAuthenticationMiddleware - 服务器无法在发送 HTTP header 后附加 header ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29824064/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com