Sam*_*les 8 oauth asp.net-web-api owin katana
我一直在尝试将一些OWIN中间件插入到现有的WebApi项目中.我的初创公司最初只包含以下几行:
application.UseOAuthBearerAuthentication(newOAuthBearerAuthenticationOptions());
application.UseWebApi(config);
Run Code Online (Sandbox Code Playgroud)
有了这个配置,我间歇性地,主要是在iisreset之后,接收到由中间件试图添加标头但是在响应发送后引起的格式错误的响应(由fiddler确定),这被报告为异常:
Server cannot append header after HTTP headers have been sent.
Run Code Online (Sandbox Code Playgroud)
我重新编译了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
Run Code Online (Sandbox Code Playgroud)
所以它看起来像中间件的响应处理部分,遵循俄罗斯玩偶模型试图修改标题,但响应已经在前一阶段完成.我尝试添加不同的阶段标记来控制这种行为,但似乎没有任何帮助.
看到这种痕迹后,令人惊讶的是,它并没有一直发生.我用更小的实现编写了我自己的这个中间件版本,在注册之后,代替MS,我确实开始在每个请求上看到错误,我想知道它是否总是被抛出,但是被吞噬了有时还是小提琴手没有等待足够长的时间才能看到它.
我目前最好的猜测是,由于对Owin使用不同的HttpConfiguration而不是WebApi设置,这个问题正在发生.不幸的是,我无法交换整个HTTPApplication并转到OWIN锁定库存,因为委托处理程序在OWIN中的不同上下文中运行,在那里您无法访问路由数据,因为这会破坏很多我们现有的基础设施.
可以给我任何关于这里发生了什么的指示,这是一个支持的场景吗?我错过了一些明显的东西吗
Sam*_*les 11
好吧,我已经解决了!
简答
如果您使用两个HttpConfiguration实例,则会出现此问题.您必须确保application.UseWebApi(config);对您的webapi配置和对您的webapi配置使用相同的HttpConfiguration .
我猜这是因为除非你使用相同的配置,否则运行时无法知道响应何时准备发送,因为没有一个地方它可以确定是否所有你的处理程序已经运行.
中等大小的答案
转换现有的webapi应用程序时,通常会在global.asax application_start处理程序中使用容器引导程序和web api配置注册.迁移到OWIN时,您要做的第一件事就是添加一个Startup类,您可以通过它来配置您的OWIN应用程序appbuilder.在这种情况下,很容易遵循纯OWIN示例并在您的新startup注册中使用新的HttpConfiguration GlobalConfiguration.你最终会得到类似的东西:
Global.asax中:
protected void Application_Start()
{
var config = GlobalConfiguration.Configuration;
Bootstrapper.Run(config);
WebApiConfig.Register(config);
}
Run Code Online (Sandbox Code Playgroud)
Startup.cs:
public void Configuration(IAppBuilder application)
{
var config = new HttpConfiguration();
application.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions());
application.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
config.MapHttpAttributeRoutes();
application.UseWebApi(config);
}
Run Code Online (Sandbox Code Playgroud)
当你真正需要的是:
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);
}
Run Code Online (Sandbox Code Playgroud)
更长的答案
你可能会认为这是相当明显的,如果你仔细地按照这些例子,你很快就会想到这一点,你就是对的.这是我在遇到问题后不久尝试的(我没有写原始代码;)).遗憾的是,如果您使用WebApi项目中使用的一些标准web.configs尝试上述操作,您将遇到许多其他问题,这些问题会导致您认为可能与原始问题相关的问题,但事实并非如此.
问题:每个请求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>
Run Code Online (Sandbox Code Playgroud)
问题:发出响应后无法重定向/ 404 在发出401后重定向到login.aspx.
解决方案:您需要取消注册formsAuthentication模块:
<!-- language: lang-xml -->
<modules runAllManagedModulesForAllRequests="true">
<remove name="FormsAuthentication" />
</modules>
Run Code Online (Sandbox Code Playgroud)
问题: "消息":"找不到与请求URI匹配的HTTP资源' http:// blah '.","messageDetail":"找不到与名为'blah'的控制器匹配的类型."
解决方案:这是一个微妙的问题.我们使用委托处理程序来扫描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
}
Run Code Online (Sandbox Code Playgroud)
现在,我们在OWIN下面的问题是controllerSelector.SelectController(在实现中System.Web.Http)内部依赖于MS_RequestContextrequest属性,如果它没有找到它,那么它会抛出一个状态代码为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
}
Run Code Online (Sandbox Code Playgroud)
问题:您尝试使用以下方法解析呼叫者IP:
if (request.Properties.ContainsKey("MS_HttpContext"))
{
return ((HttpContextWrapper)request.Properties["MS_HttpContext"]).Request.UserHostAddress;
}
Run Code Online (Sandbox Code Playgroud)
解决方案:您还需要检查以下内容,以便在OWIN下工作:
if (request.Properties.ContainsKey("MS_OwinContext"))
{
OwinContext owinContext = (OwinContext)request.Properties["MS_OwinContext"];
if (owinContext != null)
{
return owinContext.Request.RemoteIpAddress;
}
}
Run Code Online (Sandbox Code Playgroud)
而且......我们现在工作得很好!如果从OWIN获得更多的跟踪输出,那么解决这个问题会容易得多,但不幸的是,katana项目中的很多中间件在跟踪前端有点安静,希望这是随着时间的推移会得到解决的问题!
希望这可以帮助.
| 归档时间: |
|
| 查看次数: |
2921 次 |
| 最近记录: |