ASP.NET Web API的安全管道
本篇体验ASP.NET Web API的安全管道。这里的安全管道是指在请求和响应过程中所经历的各个组件或进程,比如有IIS,HttpModule,OWIN,WebAPI,等等。在这个管道中大致分两个阶段,一个是验证阶段,另一个是授权阶段。
在ASP.NET Web API v1版本的时候,安全管道大致是这样的:
→ Authentication,请求来到IIS中的HttpModule
→ Authenticatin, 请求来到API的HttpMessageHandler
→ Authorization, 请求来到Authorization Filter
→ Authorization, 请求来到Controller
当ASP.NET Web API来到v2版本的时候,安全管道大致是:
→ 请求来到Host中的OWIN组件
→ 请求来到MessageHandler,全局或按每个请求
→ 请求来到Authentication Filter
→ 请求来到Authorization Filter
可见,加入了OWIN组件,OWIN是开源的, Microsoft在此基础上开发出了Katana验证中间件。
我们知道,ASP.NET Web API的宿主有两种方式:
1、Web宿主,ASP.NET, IIS
2、自宿主,WCF,.NET进程
如果把OWIN考虑进去,那就是:
1、IIS→ASP.NET+OWIN Bridge→ OWIN→Web API + OWIN Adapter
2、Process/Host+OWIN Bridge→OWIN→Web API + OWIN Adapter
一、了解管道中的各个组件
1.1 OWIN中间件
public class AuthenticationMiddleware
{
private readonly Func<IDictionary<string, object>, Task> _next; public AuthenticationMiddleware(Func<IDictionary<string, object>, Task> next)
{
_next = next;
} public async Task Invoke(IDictionary<string, object> env)
{
//检查env集合,进行验证
env["server.user"] = CreatePrincipal();//设置principal;
await _next(env);
}
}
OWIN中间件的大致工作原理是:请求中的Header,Body,路由等信息被放在了IDictionary<string, object>这个字典集合中,并且提供了Invoke方法,把获取到的用户信息放在env["server.user"]中,并且调用一个动作处理IDictionary<string, object>集合。
1.2 Katana Authentication Middleware
这是Microsoft基于OWIN开发出来的验证组件,大致是:
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticaitonOptions{
AuthenticationType = "Cookies",
//more
}); app.UseGoogleAuthentication(new GoogleAuthenticationOptions{
AuthenticationType = "Google";
//more
}); app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions{
AuthenticationType = "Bearer";
// more
})
}
}
以上,至少可以看出,可以为OWIN组件选择验证方式。
1.3 Message Handler
实施在全局或某个请求上。大致是:
public class MyHandler : DelegatingHandler
{
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
//检查请求 var response = await base.SendAsync(request, cancellationToken); //检查响应
return response;
}
}
Message Handler从ASP.NET WEB API 2以后就不存在了。
1.4 Authentication Filter 验证过滤器
可以在全局配置:
WebApiConfig.cs
config.Filters.Add(new HostAuthenticationFilter("Bearer"));
当然过滤器也可以放在控制器和方法层面:
[HostAuthentication("Bearer")]
public class TestController : ApiController
{
[HostAuthentication("Google")]
public HttpResponseMessage Get(){}
[OverrideAuthentication]
[HostAuthentication("Cookies")]
public HttpResponseMessage Delete(){}
}
1.5 Authorization Filter 授权过滤器
[Authorize]
public class DataController : ApiController
{
[AllowAnonymous]
public Data Get(){} [Authorize(Role = "Foo")]
public HttpResponseMessage Delete(int id){}
}
如果授权失败,返回401报错。
1.6 获取用户的Identity
通过ApiController的User属性获取到用户的Identity。注意,User属性值可能为null。
二、通过例子来体验安全管道
2.1 自定义HttpModule
首先,请求过来,肯定要通过HttpModule。我们需要自定义一个HttpModule,通过一个版主方法把当前的用户信息打印出来。
namespace SecurityPipeline
{
public class HttpModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.BeginRequest += context_BeginRequest;
} void context_BeginRequest(object sender, EventArgs e)
{
Helper.Write("HttpModule", HttpContext.Current)
} public void Dispose()
{ }
}
} namespace SecurityPiepeline
{
public static class Helper
{
public static void Write(string state, IPrincipal principal)
{
Debug.WriteLine("------------" + stage + "--------");
if(principal == null || principal.Identity == null || !principal.Identity.IsAuthenticated)
{
Debug.WriteLine("anonymous user");
}
else
{
Debug.WriteLine("User:" + principal.Identity.User);
} Debug.WriteLine("\n");
}
}
}
可见,HttpContext.Current是IPrincipal类型。
然后这是一个Web项目,需要把HTTP module注册一下。
<configuration>
<system.webServer>
<modules>
<add name="DemoModule" type="SecurityPipeline.HttpModule"/>
</modules>
</system.webServer>
</configuration>
如果此时项目下有一个default.html页面的话,运行项目,展示default.html的时候,控制台打印出如下信息:
-----HttpModule-------
anonymouse
显然,请求过来,自定义的Http Module起了作用,但目前还不能从IPrincipal中拿到User信息。
2.2 安装ASP.NET Web API 2
2.3 创建控制器
using System.Net.Http;
public class TestController : ApiController
{
public IHttpActionResult Get()
{
Helper.Write("Controller", User); //获取用户也可以这样写
//Helper.Write("Controller",Request.GetRequestContext().Principal);
return Ok();
}
}
以上,通过ApiController的User属性获取到IPincipal类型。
2.4 安装Microsoft.Owin.Host.SystemWeb
2.5 安装Microsoft. ASP.NET Web API 2.1 OWIN
2.6 创建Startup类
using OWin;
using System.Web.Http; namespace SecurityPopeline
{
public class Startup
{
public void Configuraiton()
{
var configuration = new HttpConfiguration();
configuration.Routes.MapHttpRoute("default", "api/{controller}"); }
}
}
这里,让WEB API的HttpConfiguraton实例赋值给类OWIN的IAppBuilder的UseWebApi方法。
2.7 请求路由:localhsot:8000/api/test
显示
------HttpModule--------
anonymous user
------Controller--------
anonymous user
可见,请求一路经过管道中的HttpModule和Controller,但依然没有拿到用户信息。
2.8 创建TestMiddleware类
进入HttpModule之后,和进入Controller之前,这里是OWIN组件的生存之地。
using Microsoft.Owin; namespace SecurityPopeline.Pipeline
{
public class TestMiddleware
{
private Func<IDictionary<string, object>, Task> _next;
public TestMiddleware(Func<IDictionary<string, object>, Task> next)
{
_next = next;
} public async Task Invoke(IDictionary<string, object> env)
{
var context = new OwinContext(env);
Helper.Write("Middleware", context.Request.User);
await _next(env);
}
}
}
2.9 Startup类中增加有关TestMiddleware部分
using OWin;
using System.Web.Http; namespace SecurityPopeline
{
public class Startup
{
public void Configuraiton(IAppBuilder app)
{
var configuration = new HttpConfiguration();
configuration.Routes.MapHttpRoute("default", "api/{controller}"); app.Use(typeo(TestMiddleware)); app.UseWebApi(configuration);
}
}
}
3.10 请求路由:localhsot:8000/api/test
显示
------HttpModule--------
anonymous user
------Middleware--------
anonymous user
------Controller------
anonymous user
可见,请求一路过来历经管道中的HttoModule, OWIN, 最后到达Controller,依然没有获取到用户信息。
3.11 添加TestAuthenticationFilterAttribute类
在OWIN和Controller之间,还有验证的接口,这也是安全管道中的一个重要环节。
using System.Web.Http.Filters;
using System.Threading.Tasks; namespace SecurityPipeline.Pipeline
{
public class TestAuthenticationFilterAttribute : Attribute, IAuthenticationFilter
{
public async Task AuthenticateAsync(HttpAuthenticationContext context)
{
Helper.Write("AuthenticationFilter", context.ActionContext.RequestContext.Principal, CancellationToken..)
} public async Task ChallengeAsync(HttpAuthenticationContext context, CancellationToken..)
{ } public bool AllowMultiple
{
get {
return false;
}
}
}
}
控制器增加过滤特性
using System.Net.Http; [TestAuthenticationFilter]
public class TestController : ApiController
{
public IHttpActionResult Get()
{
Helper.Write("Controller", User); //获取用户也可以这样写
//Helper.Write("Controller",Request.GetRequestContext().Principal);
return Ok();
}
}
3.12 请求路由:localhsot:8000/api/test
显示
------HttpModule--------
anonymous user
------Middleware--------
anonymous user
------AuthenticationFilter--------
anonymous user
------Controller------
anonymous user
可见,请求路径安全管道中的HttpModule,OWIN,验证,依然没有获取到用户信息。
3.13 增加TestAuthorizationFilterAttrbute类
在经过验证特性,以及进入Controller或Action之前,安全管道中还有一个重要的成员,就是授权特性。
public class TestAuthorizationFilterAttribute : AuthorizeAttibute
{
protected override bool IsAuthorized(HttpActionContext actionContext)
{
Helper.Write("AuthorizationFilter", actionContext.RequestContext.Prioncipal); return base.IsAuthorized(actionContext);
}
}
控制器增加授权特性
using System.Net.Http; [TestAuthenticationFilter]
[TestAuthorizationFilter]
public class TestController : ApiController
{
public IHttpActionResult Get()
{
Helper.Write("Controller", User); //获取用户也可以这样写
//Helper.Write("Controller",Request.GetRequestContext().Principal);
return Ok();
}
}
3.14 请求路由:localhsot:8000/api/test
显示
------HttpModule--------
anonymous user
------Middleware--------
anonymous user
------AuthenticationFilter--------
anonymous user
------AuthorizationFilter--------
anonymous user
并报错:Authorization has been denied for this request
可见,在请求还没有到达Controller之前,就开始报错了。
于是,修改TestAuthorizationFilterAttrbute类如下:
public class TestAuthorizationFilterAttribute : AuthorizeAttibute
{
protected override bool IsAuthorized(HttpActionContext actionContext)
{
Helper.Write("AuthorizationFilter", actionContext.RequestContext.Prioncipal); //return base.IsAuthorized(actionContext);
return true;
}
}
3.15 请求路由:localhsot:8000/api/test
显示
------HttpModule--------
anonymous user
------Middleware--------
anonymous user
------AuthenticationFilter--------
anonymous user
------AuthorizationFilter--------
anonymous user
------Controller--------
anonymous user
可见,路由一路经过安全管道中的HttpModule, OWIN, AuthenticaitonFilter, AuthorizationFilter, Controller,依然没有获取到用户信息?
3.16 用户信息从哪里注入呢?
接下来要修改TestMiddleware类
using Microsoft.Owin;
using System.Security.Principal; namespace SecurityPopeline.Pipeline
{
public class TestMiddleware
{
private Func<IDictionary<string, object>, Task> _next;
public TestMiddleware(Func<IDictionary<string, object>, Task> next)
{
_next = next;
} public async Task Invoke(IDictionary<string, object> env)
{
var context = new OwinContext(env); //authentication
//new string[]数组存放用户
context.Request.User = new GenericPrincipal(new GenericIdentity("dom"),new string[]{}); Helper.Write("Middleware", context.Request.User);
await _next(env);
}
}
}
3.17 请求路由:localhsot:8000/api/test
显示
------HttpModule--------
anonymous user
------Middleware--------
User: dom
------AuthenticationFilter--------
User: dom
------AuthorizationFilter--------
User: dom
------Controller--------
User: dom
总结:请求一路过来,会经过安全管道中的HttpModule, OWIN,AuthenticaitonFilter, AuthorizationFilter, Controller,最后到达Action, 而用户信息可以在OWIN中注入。
ASP.NET Web API的安全管道的更多相关文章
- ASP.NET Web API标准的“管道式”设计
ASP.NET Web API的核心框架是一个消息处理管道,这个管道是一组HttpMessageHandler的有序组合.这是一个双工管道,请求消息从一端流入并依次经过所有HttpMessageHan ...
- ASP.NET Web API的消息处理管道: Self Host下的消息处理管道[上篇]
ASP.NET Web API的消息处理管道: Self Host下的消息处理管道[上篇] ASP.NET Web API服务端框架核心是一个独立于具体寄宿环境的消息处理管道,它不关心请求消息来源于何 ...
- ASP.NET Web API的消息处理管道: HttpRoutingDispatcher
ASP.NET Web API的消息处理管道: HttpRoutingDispatcher 认情况下,作为消息处理管道“龙头”的HttpServer的Dispatcher属性返回一个HttpRouti ...
- ASP.NET Web API的消息处理管道:"龙头"HttpServer
ASP.NET Web API的消息处理管道:"龙头"HttpServer 一般来说,对于构成ASP.NET Web API消息处理管道的所有HttpMessageHandler来 ...
- ASP.NET Web API 2 消息处理管道
Ø 前言 ASP.NET 的应用程序都会有自己的消息处理管道和生命周期,比如:ASP.NET Web 应用程序(Web Form).ASP.NET MVC,还有本文将讨论的 ASP.NET Web ...
- ASP.NET Web API标准的“管道式”设计
详见:http://www.cnblogs.com/artech/p/asp-net-web-api-pipeline.html http://www.codeproject.com/Articles ...
- ASP.NET Web API WebHost宿主环境中管道、路由
ASP.NET Web API WebHost宿主环境中管道.路由 前言 上篇中说到ASP.NET Web API框架在SelfHost环境中管道.路由的一个形态,本篇就来说明一下在WebHost环境 ...
- ASP.NET Web API Selfhost宿主环境中管道、路由
ASP.NET Web API Selfhost宿主环境中管道.路由 前言 前面的几个篇幅对Web API中的路由和管道进行了简单的介绍并没有详细的去说明一些什么,然而ASP.NET Web API这 ...
- ASP.NET Web API 管道模型
ASP.NET Web API 管道模型 前言 ASP.NET Web API是一个独立的框架,也有着自己的一套消息处理管道,不管是在WebHost宿主环境还是在SelfHost宿主环境请求和响应都是 ...
随机推荐
- 洛谷P1738 洛谷的文件夹
原题目:点我 题目是一个略水的题,我机制地用面向对象做了...所以代码量急剧加大,100行233 模拟即可,字符串处理麻烦点.如果没有找到子文件夹就新建文件夹,如果有就进入该文件夹. 提示:高能,指针 ...
- php中or的含义
or其实是Php中的短路或 经常看到这样的语句: $file = fopen($filename, r) or die("抱歉,无法打开: $filename"); or在这里是这 ...
- ASP.NET访问网络映射盘&实现文件上传读取功能
最近在改Web的时候,遇到一个问题,要跨机器访问共享文件夹,以实现文件正常上传下载功能. 要实现该功能,可以采用HTTP的方式,也可以使用网络映射磁盘的方式,今天主要给大家分享一下使用网络映射磁盘的方 ...
- SQL删除重复数据
--首先将不是重复的数据提取出来,保存到一个临时表中 select distinct * into #temp from JX_Score --然后删除原来的表 delete from JX_Scor ...
- 【JSP】自定义标签开发入门
JSP 自定义标签 自定义标签是用户定义的JSP语言元素.当JSP页面包含一个自定义标签时将被转化为servlet,标签转化为对被 称为tag handler的对象的操作,即当servlet执行时We ...
- js 图片预览
图片预览 $('#pac_recipe').change(function() { var imgsrc = ''; ]) { //chrome firefox imgsrc = window.URL ...
- Oracle数据库11g基于rehl6.5的配置与安装
REDHAT6.5安装oracle11.2.4 ORACLE11G R2官档网址: http://docs.oracle.com/cd/E11882_01/install.112/e24326/toc ...
- ORACLE升级的一些事
一.SQL> @?/rdbms/admin/catupgrd.sql 说明:? 代表 ORACLE_HOME,在Linux中可能以 $ORACLE_HOME表示. @ 表示执行脚本 参考: ht ...
- C++混合编程之idlcpp教程Lua篇(3)
上一篇 C++混合编程之idlcpp教程Lua篇(2) 是一个 hello world 的例子,仅仅涉及了静态函数的调用.这一篇会有新的内容. 与LuaTutorial0相似,工程LuaTutoria ...
- Dynamic CRM 2013学习笔记(十九)自定义审批流1 - 效果演示
CRM的项目,审批流是一个必须品.为了更方便灵活地使用.配置审批流,我们自定义了一整套审批流.首先来看下它的效果: 1. 审批模板 这是一个最简单的审批流,首先指定审批实体,及相关字段,再配置流程节点 ...