将OWIN App部署在IIS上                                           

要想将Owin App部署在IIS上,只添加Package:Microsoft.OWIN.Host.SystemWeb包即可。它提供了所有Owin配置,Middleware注册等方面的Api.我们需要做的其实和SelfHost差不多。

  • 我们依然需要实现Startup类,但是不是通过WebApp来启动了。我们需要通过将Startup类打上[assembly: OwinStartup(typeof(Startup))]来定义这是OWIN的Startup类,当应用运行的时候会自动发现并调用Configuration方法
  • 在Startup类的Configuration方法中我们可以配置我们的Middleware。

SystemWeb其实是实现了一个OwinHttpModule来根据MiddleWare的需求注册IIS的各种事件,然后执行相关的Middleware.

先看一下IIS集成模式的HttpRequest处理的管道模型。

我们的Middleware运行在IIS管道中哪个环节是通过调用appBuilder.UseStageMarker(PipelineStage.Authenticate);这个扩展方法来定义的。其中PipelineState有如下可选值:

public enum PipelineStage
{
Authenticate = ,
PostAuthenticate = ,
Authorize = ,
PostAuthorize = ,
ResolveCache = ,
PostResolveCache = ,
MapHandler = ,
PostMapHandler = ,
AcquireState = ,
PostAcquireState = ,
PreHandlerExecute = ,
}

以上枚举值对应IIS管道中的对应环节。Stage的指定有如下规则:

1. 默认的Stage为PreHandlerExecute

2. 每次UseStageMaker的调用指定了该次调用与前一次调用之间的注册的Middleware均在该次UseStageMaker中指定的Stage中运行

3. Stage的指定顺序应该与IIS管道的处理顺序一致

4. 如果Stage的指定顺序与IIS管道处理顺序不一致,在后面指定的在IIS管道中靠前的Stage会覆盖在其前面指定的在IIS管道中靠后的Stage.

听上去有点绕口。其实理解了原因和实现就容易理解了。这种规则的原因是:IIS管道是有固定顺序的,而OWIN中Middleware的执行也是按照注册的先后顺序的,而当OWIN部署在IIS中时Middleware的执行又是依赖与IIS管道事件的,所以只有当指定的Stage顺序与IIS管道顺序一致时才不会有冲突。

为Web Api添加Authenticate OWIN Middleware                                 

我们首先创建一个普通的web api工程,添加如下接口,然后部署在IIS上。

[RoutePrefix("api/persons")]
public class PersonController : ApiController
{
[Route("{id}")]
[Authorize]
// GET api/values/5
public string Get(int id)
{
return "Jensen";
}
}

这时候如果去访问该接口会得到401未授权的错误。

接下来通过添加AuthMiddleware来作为WebApi验证模块。

首先添加AuthenticateMiddleware

public class AuthenticateMiddleware
{
private Func<IDictionary<string, object>, Task> nextAppFunc;
public AuthenticateMiddleware(Func<IDictionary<string, object>, Task> nextMiddleWareFunc)
{
nextAppFunc = nextMiddleWareFunc;
} public async Task Invoke(IDictionary<string, object> parameters)
{
Trace.WriteLine("Auth Middleware");
Trace.WriteLine(HttpContext.Current.CurrentNotification); var identity = new GenericIdentity("jensen");
parameters["server.User"] = new GenericPrincipal(identity, new string[] { "admin" });
if (nextAppFunc != null)
{
await nextAppFunc.Invoke(parameters);
}
}
}

然后添加Startup类来注册AuthenticateMiddleware,并指定运行Stage为Authenticate.

[assembly: OwinStartup(typeof(OwinIISHost.Startup))]
namespace OwinIISHost
{
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
appBuilder.Use<AuthenticateMiddleware>();
appBuilder.UseStageMarker(PipelineStage.Authenticate); }
}
}

这样当我们再次访问前面定义的api时,就能得到期望的结果了。因为在AuthenticateMiddleware中我们对所有请求都通过了验证。

这里一开始有点疑问,WebApi中是根据HttpContext.User来获取当前请求的用户信息的。但是我们在AuthenticateMiddleware中并没有直接给HttpContext.User赋值,而是将User信息赋值到key 为server.user的OWIN环境参数中。这中间有个断档。通过查看SystemWeb Package的源码,解答了我的疑问。

首先,我们的Middleware中接收到的OWIN环境参数类型为AspNetDictionary,可以查看其实现:

internal AspNetDictionary(IPropertySource propertySource)//构造函数,这里propertySource由外部传入
{
_propertySource = propertySource;
} object IDictionary<string, object>.this[string key]//索引属性,我们设置User信息给server.user key时该方法会被调用
{
get
{
object value;
return PropertiesTryGetValue(key, out value) ? value : Extra[key];
}
set
{
if (!PropertiesTrySetValue(key, value))
{
StrongExtra[key] = value;
}
}
} private bool PropertiesTrySetValue(string key, object value)
{
switch (key.Length)
{
//....ignore some code here
case :
if (string.Equals(key, "server.User", StringComparison.Ordinal))
{
ServerUser = (IPrincipal)value;//赋值给ServerUser属性
return true;
}
break;
//...ignore some code here
}
return false;
} internal IPrincipal ServerUser
{
get
{
return _propertySource.GetServerUser();
}
set
{
_propertySource.SetServerUser(value);//最后还是调了propertySource的SetServerUser方法
}
}

那现在关键就看_propertySource是如何实现的了。通过查看创建AspNetDictionary的代码发现_propetySource为OwinCallContext类型的实例。看看它对SetServerUser的实现:

void AspNetDictionary.IPropertySource.SetServerUser(IPrincipal value)
{
_httpContext.User = value;//真相大白,其实当我们给server.User key赋值时,value其实直接就赋给了HttpContext。
Thread.CurrentPrincipal = value;
}

参考:

AspNetKatana源码,包含SystemWebPackage

为IIS Host ASP.NET Web Api添加Owin Middleware的更多相关文章

  1. 为Asp.Net Web Api添加Http基本认证

    Asp.net Web Api提供了RESTFul web服务的编程接口.默认RESTFul 服务没有提供任何验证或者基于角色的验证,这显然不适合Put.Post.Delete这些操作.Aps.net ...

  2. ASP.NET Web API与Owin OAuth:使用Access Toke调用受保护的API

    在前一篇博文中,我们使用OAuth的Client Credential Grant授权方式,在服务端通过CNBlogsAuthorizationServerProvider(Authorization ...

  3. asp.net web api添加统一异常处理

    1.自定义异常处理过滤器 /// <summary> /// 自定义异常处理过滤器 /// </summary> public class CustomExceptionFil ...

  4. ASP.NET Web API与Owin OAuth:调用与用户相关的Web API

    在前一篇博文中,我们通过以 OAuth 的 Client Credential Grant 授权方式(只验证调用客户端,不验证登录用户)拿到的 Access Token ,成功调用了与用户无关的 We ...

  5. 自定义DelegatingHandler为ASP.NET Web Api添加压缩与解压的功能

    HTTP协议中的压缩 Http协议中使用Accept-Encoding和Content-Encoding头来表示期望Response内容的编码和当前Request的内容编码.而Http内容的压缩其实是 ...

  6. Asp.net Web Api添加异常筛选器

    一.定义一个异常筛选器 using System;using System.Collections.Generic;using System.Linq;using System.Web;using S ...

  7. ASP.NET Web API与Owin OAuth:调用与用户相关的Web API(非第三方登录)

    授权完成添加属性 ClaimsIdentity oAuthIdentity = await CreateAsync(user/*userManager*/, OAuthDefaults.Authent ...

  8. [转] JSON Web Token in ASP.NET Web API 2 using Owin

    本文转自:http://bitoftech.net/2014/10/27/json-web-token-asp-net-web-api-2-jwt-owin-authorization-server/ ...

  9. JSON Web Token in ASP.NET Web API 2 using Owin

    In the previous post Decouple OWIN Authorization Server from Resource Server we saw how we can separ ...

随机推荐

  1. HTTP与抓包

    HTTP就是超文本传输协议,底层使用socket TCP长连接,基于请求与响应,是同步请求. socket 绝对多数语言都是支持socket的,底层走的是二进制传输. HTTP协议实际上是对Socke ...

  2. Contest-hunter 暑假送温暖 SRM08

    01-07都没写...然后突然来写貌似有点突兀啊...不管了,难得前排记录一下... 吐槽一下赛制...不得不说很强... cf 套oi...很创新...不过还是兹磁ACM或者CF A-1 数据才2& ...

  3. ScrollView嵌套使用ListView冲突的解决与分析

    因为ScrollView与ListView都是具有滚动条的控件,所以嵌套在一起使用的时候可能会出现事件的冲突,比如我就遇见了ListView中只显示一条数据的问题.解决的办法,就是自定义了一个List ...

  4. JNI简单HelloWorld

    1.编写Java代码 建立hello目录,编写HelloWorld.java: class HelloWorld { public native void displayHelloWorld(); s ...

  5. 利用$http获取在服务器的json数据

    以下是存储在web服务器上的 JSON 文件: http://www.runoob.com/try/angularjs/data/Customers_JSON.php { "records& ...

  6. css3 放大缩小代码

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  7. MySQL 入门篇

    历史 MySQL 是由 David Axmark.Allan Larsson 和 Michael Widenius 3 个瑞典人于 20 世纪 90 年代开发的一个关系型数据库.MySQL 之名取自创 ...

  8. opensack-mitaka网络性能测试shaker

    一.项目介绍 Shaker项目是由Mirantis发起,专门针对OpenStack网络性能的测试工具.通过模拟不同的网络场景和heat模板,创建虚拟机,并在虚拟机里运行iperf.iperf3.net ...

  9. opencv:通过滑动条调节亮度和对比度

    示例代码: #include <opencv.hpp> using namespace cv; using namespace std; void on_change(int, void* ...

  10. Python基础学习(第8天)

    先补充些iter函数的用法:iter()其实就是一个迭代器,参数可传个list.dict等等,然后可通过调用next函数获取下一个元素,默认并未指向对象的第一个元素,可理解为指向了第一个元素的前面的位 ...