【ASP.NET MVC系列】浅谈ASP.NET MVC资源过滤和授权
最近比较忙,博客很久没更新了,很多博友问何时更新博文,因此,今天就花了点时间,写了本篇文章,但愿大家喜欢。
本篇文章不适合初学者,需要对ASP.NET MVC具有一定基础。
本篇文章主要从ASP.NET MVC 基架角度去分析MVC框架是如何实现资源过滤,资源授权,感兴趣的,欢迎阅读。
相关文章,请参与ASP.NET MVC系列
一 ASP.NET MVC框架验证机制
为了更加透彻地了解MVC的过滤机制,我简要地画了如下UML图。
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited=true, AllowMultiple=true)] public class AuthorizeAttribute : FilterAttribute, IAuthorizationFilter { // Fields private string _roles; private string[] _rolesSplit = new string[0]; private static readonly char[] _splitParameter = new char[] { ',' }; private readonly object _typeId = new object(); private string _users; private string[] _usersSplit = new string[0]; // Methods protected virtual bool AuthorizeCore(HttpContextBase httpContext) { if (httpContext == null) { throw new ArgumentNullException("httpContext"); } IPrincipal user = httpContext.User; if (!user.Identity.IsAuthenticated) { return false; } if ((this._usersSplit.Length != 0) && !this._usersSplit.Contains<string>(user.Identity.Name, StringComparer.OrdinalIgnoreCase)) { return false; } if ((this._rolesSplit.Length != 0) && !this._rolesSplit.Any<string>(new Func<string, bool>(user.IsInRole))) { return false; } return true; } private void CacheValidateHandler(HttpContext context, object data, ref HttpValidationStatus validationStatus) { validationStatus = this.OnCacheAuthorization(new HttpContextWrapper(context)); } protected virtual void HandleUnauthorizedRequest(AuthorizationContext filterContext) { filterContext.Result = new HttpUnauthorizedResult(); } public virtual void OnAuthorization(AuthorizationContext filterContext) { if (filterContext == null) { throw new ArgumentNullException("filterContext"); } if (OutputCacheAttribute.IsChildActionCacheActive(filterContext)) { throw new InvalidOperationException(MvcResources.AuthorizeAttribute_CannotUseWithinChildActionCache); } if (!filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true) && !filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true)) { if (this.AuthorizeCore(filterContext.HttpContext)) { HttpCachePolicyBase cache = filterContext.HttpContext.Response.Cache; cache.SetProxyMaxAge(new TimeSpan(0L)); cache.AddValidationCallback(new HttpCacheValidateHandler(this.CacheValidateHandler), null); } else { this.HandleUnauthorizedRequest(filterContext); } } } protected virtual HttpValidationStatus OnCacheAuthorization(HttpContextBase httpContext) { if (httpContext == null) { throw new ArgumentNullException("httpContext"); } if (!this.AuthorizeCore(httpContext)) { return HttpValidationStatus.IgnoreThisRequest; } return HttpValidationStatus.Valid; } internal static string[] SplitString(string original) { if (string.IsNullOrEmpty(original)) { return new string[0]; } return original.Split(_splitParameter).Select((<>c.<>9__19_0 ?? (<>c.<>9__19_0 = new Func<string, <>f__AnonymousType1<string, string>>(<>c.<>9.<SplitString>b__19_0)))).Where((<>c.<>9__19_1 ?? (<>c.<>9__19_1 = new Func<<>f__AnonymousType1<string, string>, bool>(<>c.<>9.<SplitString>b__19_1)))).Select((<>c.<>9__19_2 ?? (<>c.<>9__19_2 = new Func<<>f__AnonymousType1<string, string>, string>(<>c.<>9.<SplitString>b__19_2)))).ToArray<string>(); } // Properties public string Roles { get { return (this._roles ?? string.Empty); } set { this._roles = value; this._rolesSplit = SplitString(value); } } public override object TypeId { get { return this._typeId; } } public string Users { get { return (this._users ?? string.Empty); } set { this._users = value; this._usersSplit = SplitString(value); } } // Nested Types [Serializable, CompilerGenerated] private sealed class <>c { // Fields public static readonly AuthorizeAttribute.<>c <>9 = new AuthorizeAttribute.<>c(); public static Func<string, <>f__AnonymousType1<string, string>> <>9__19_0; public static Func<<>f__AnonymousType1<string, string>, bool> <>9__19_1; public static Func<<>f__AnonymousType1<string, string>, string> <>9__19_2; // Methods internal <>f__AnonymousType1<string, string> <SplitString>b__19_0(string piece) { return new { piece = piece, trimmed = piece.Trim() }; } internal bool <SplitString>b__19_1(<>f__AnonymousType1<string, string> <>h__TransparentIdentifier0) { return !string.IsNullOrEmpty(<>h__TransparentIdentifier0.trimmed); } internal string <SplitString>b__19_2(<>f__AnonymousType1<string, string> <>h__TransparentIdentifier0) { return <>h__TransparentIdentifier0.trimmed; } } } Collapse MethodsView Code 通过反汇编,得出如下结论:
1.提供四个虚方法OnAuthorization(AuthorizationContext filterContext),AuthorizeCore(HttpContextBase httpContext),HandleUnauthorizedRequest(AuthorizationContext filterContext)和OnCacheAuthorization(HttpContextBase httpContext)。
四个方法作用和关系是怎样的呢
OnAuthorization表示请求过程时身份验证,AuthorizeCore表示支持用户自定义身份验证,HandleUnauthorizeRequest表示当AuthorizeCore方法验证失败时,执行的操作,OnCacheAuthorization表示模块缓存权限。
(一) ASP.NET MVC 基架提供的验证
只需在需要验证的资源生加上[Authorize]特性即可。
[Authorize] public ActionResult Index() { return View(); ; }
(二) 实现自定义验证机制
当未给Index() action添加验证限制时,匿名用户名能直接访问 /Default/Index
当给Index() action添加验证限制时,匿名用户名不能直接访问 /Default/Index,而被强制重定型到登陆页面,要求用户登陆。
(三) ASP.NET MVC验证级别
ASP.NET MVC提供了四种基本验证模式:匿名,全局,控制器和Action
1.匿名
public class DefaultController : Controller { [AllowAnonymous] public ActionResult Index() { return View(); } }
2.action
public class DefaultController : Controller { [CustomAuthorize] public ActionResult Index() { return View(); } }
3.Controller
[CustomAuthorize] public class DefaultController : Controller { public ActionResult Index() { return View(); } }
4.全局
public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new CustomAuthorizeAttribute());//给自定义验证注册 filters.Add(new HandleErrorAttribute()); } }
扩展,当添加多个验证时,程序时如何执行的?通古Order值顺序执行
[Filter1(Order = 3)] [Filter2(Order = 2)] [Filter3(Order = 1)] public ActionResult Index() { return View(); ; }
三 总结
本篇文章主要从ASP.NET MVC框架设计角度,运用PD工具,通过UML分析ASP.NET MVC是如何实现资源过滤,如何实现权限控制等功能的,更细粒度的技术文章,在后续博文中更新。
- 【EntityFramework系列教程三,翻译】在ASP.NET MVC程序中使用EntityFramework对数据进行排序、过滤筛选以及实现分页
- 【ASP.NET MVC系列】浅谈数据注解和验证
- 【ASP.NET MVC系列】浅谈MVC
- 【ASP.NET MVC系列】浅谈NuGet在VS中的运用
- 【ASP.NET MVC系列】浅谈ASP.NET MVC运行过程
- 【ASP.NET MVC系列】浅谈ASP.NET MVC 视图
- 【ASP.NET MVC系列】浅谈ASP.NET 页面之间传值的几种方式
- 笨鸟先飞之ASP.NET MVC系列之过滤器(02授权过滤器)
- Easyui + asp.net MVC 系列教程 第19-23 节 完成注销 登录限制过滤 添加用户
- 【ASP.NET MVC系列】浅谈数据注解和验证
- 【ASP.NET MVC系列】浅谈表单和HTML辅助方法
- 【ASP.NET MVC系列】浅谈ASP.NET框架
- ASP.NET MVC with Entity Framework and CSS一书翻译系列文章之第三章:搜索、高级过滤和视图模型
- 成员资格、授权 – ASP.NET MVC 4 系列
- 【ASP.NET MVC系列】浅谈NuGet在VS中的运用
- 【ASP.NET MVC系列】浅谈缓存技术在ASP.NET中的运用
- Asp.net mvc项目架构分享系列之架构概览
- Asp.Net MVC中身份认证和授权
- Asp.Net MVC2 实用入门系列:ASP.NET MVC小论
- 七天学会ASP.NET MVC (四)——用户授权认证问题