MVC全局用户验证之HttpModule
在请求进入到MVC的处理mcvHandler之前,请求先到达HttpModule,因此可以利用HttpModule做全局的用户验证。
HttpModule
MVC5之前的版本基于system.web.dll库,MvcApplication继承自HttpApplication,以Http管道的方式运行,HttpApplication是整个ASP.NET基础架构的核心,HttpApplication处理请求的整个生命周期是一个相对复杂的过程,在该过程的不同阶段会触发相应的事件
名称 |
描述 |
BeginRequest |
HTTP管道开始处理请求时,会触发BeginRequest事件 |
AuthenticateRequest,PostAuthenticateRequest |
ASP.NET先后触发这两个事件,使安全模块对请求进行身份验证 |
AuthorizeRequest,PostAuthorizeRequest |
ASP.NET先后触发这两个事件,使安全模块对请求进程授权 |
ResolveRequestCache,PostResolveRequestCache |
ASP.NET先后触发这两个事件,以使缓存模块利用缓存的直接对请求直接进程响应(缓存模块可以将响应内容进程缓存,对于后续的请求,直接将缓存的内容返回,从而提高响应能力)。 |
PostMapRequestHandler |
对于访问不同的资源类型,ASP.NET具有不同的HttpHandler对其进程处理。对于每个请求,ASP.NET会通过扩展名选择匹配相应的HttpHandler类型,成功匹配后,该实现被触发 |
AcquireRequestState,PostAcquireRequestState |
ASP.NET先后触发这两个事件,使状态管理模块获取基于当前请求相应的状态,比如SessionState |
PreRequestHandlerExecute,PostRequestHandlerExecute |
ASP.NET最终通过一请求资源类型相对应的HttpHandler实现对请求的处理,在实行HttpHandler前后,这两个实现被先后触发 |
ReleaseRequestState,PostReleaseRequestState |
ASP.NET先后触发这两个事件,使状态管理模块释放基于当前请求相应的状态 |
UpdateRequestCache,PostUpdateRequestCache |
ASP.NET先后触发这两个事件,以使缓存模块将HttpHandler处理请求得到的相应保存到输出缓存中 |
LogRequest,PostLogRequest |
ASP.NET先后触发这两个事件为当前请求进程日志记录 |
EndRequest |
整个请求处理完成后,EndRequest事件被触发 |
HttpApplication提供了基于事件的扩展机制,允许程序员借助于处理管道中的事件进行处理过程扩展。在Asp.net中,提供了两种方式来解决这个问题:IHttpModule方式和golbal.asax方式。这两种方式的核心都是IHttpModule接口。
从功能上讲,HttpModule之于ASP.NET,就好比ISAPI Filter之于IIS一样。IIS将接收到的请求分发给相应的ISAPI Extension之前,注册的ISAPI Filter会先截获该请求。
当一个HTTP请求到达HttpModule时,整个ASP.NET Framework系统还并没有对这个HTTP请求做任何处理,也就是说此时对于HTTP请求来讲,HttpModule是一个HTTP请求的“必经之路”,所以可以在这个HTTP请求传递到真正的请求处理中心(HttpHandler)之前附加一些需要的信息在这个HTTP请求信息之上,或者针对截获的这个HTTP请求信息作一些额外的工作,或者在某些情况下干脆终止满足一些条件的HTTP请求,从而可以起到一个Filter过滤器的作用。
public class BasicAuthenticationHttpModule : IHttpModule { private static IAuthenticationService _authenticationService; public static void SetBasicAuthenticationValidator(IAuthenticationService authenticationService) { _authenticationService = authenticationService; } public void Init(HttpApplication context) {
//核心:用户认证事件处理 context.PostAuthenticateRequest += ContextOnAuthenticateRequest; } private static void ContextOnAuthenticateRequest(object sender, EventArgs eventArgs) { if (_authenticationService == null || HttpContext.Current == null || HttpContext.Current.User == null || HttpContext.Current.User.Identity.IsAuthenticated) return; try { IPrincipal principal = null; var headers = HttpContext.Current.Request.Headers; var authValue = headers[HttpRequestHeader.Authorization.ToString()]; //if no Basic header, don't prompt for it if (authValue == null || string.IsNullOrWhiteSpace(authValue) || !authValue.StartsWith("Basic")) { return; } //try to parse for it var parsedCredentials = ParseAuthorizationHeader(authValue); if (parsedCredentials != null) { principal = _authenticationService.ValidateCredentials( parsedCredentials.Item1, parsedCredentials.Item2); } if (principal == null) { Unauthorized(HttpContext.Current); return; } SetPrincipal(principal); } catch (SecurityException) { throw; } catch (Exception ex) { throw new SecurityException("Unexpected error. See inner exception for details.", ex); } } private static void Unauthorized(HttpContext context) { Trace.TraceWarning("Unauthorized basic credentials"); context.Response.Headers.Add("WWW-Authenticate", "Basic"); context.Response.StatusCode = 401; context.Response.StatusDescription = "Invalid credentials"; context.ApplicationInstance.CompleteRequest(); } private static Tuple<string, string> ParseAuthorizationHeader(string authHeader) { try { string base64Credentials = authHeader.Substring(6); var credentials = Encoding.ASCII.GetString(Convert.FromBase64String(base64Credentials)) .Split(new[] { ':' }); if (credentials.Length != 2 || string.IsNullOrEmpty(credentials[0]) || string.IsNullOrEmpty(credentials[1])) { return null; } return new Tuple<string, string>(credentials[0], credentials[1]); } catch (Exception exception) { Trace.TraceError("BasicAuthentication: ParseHeader " + exception); throw; } } private static void SetPrincipal(IPrincipal principal) { Thread.CurrentPrincipal = principal; HttpContext.Current.User = Thread.CurrentPrincipal; } public void Dispose() { } }
进行注册
<system.webServer> <modules> <add name="BasicAuthenticationHttpModule" type="WebApplication1.BasicAuthenticationHttpModule" /> </modules> </system.webServer> Global.asax void Application_Start(object sender, EventArgs e) { BasicAuthenticationHttpModule.SetBasicAuthenticationValidator(new AuthenticationService()); }
原文地址:https://www.cnblogs.com/soundcode/p/11393771.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 使用prepareStatement连接数据库实现增、删、改、查
- 插入排序图解与代码示例
- 初步使用Druid连接池+代码示例:对图书进行增删改查
- 创建Servlet的几种方式+web.xml中关于servlet的一些配置+浏览器、服务器交互Postman测试
- 二分法查找介绍+代码
- API文档的自动生成
- cookie创建的三个参数(有效期+有效路径+httponly)
- interface概念与代码示例,常量接口和标记接口,与abstract的区别
- Java8异步编程就是拽
- 如果try{}里面有一个return语句,那么紧跟着这个try后的finally{}里面的代码会不会执行?
- 二叉查找树代码java+运行结果
- 全选
- 在控制台,递归显示文件夹下所有文件目录代码+ 运行结果
- 使用bootstrap时下拉菜单失效问题解决
- 使用文件字节输出流FileOutputStream写入文件