ASP.NET MVC自定義授權(quán)過(guò)濾器
一、授權(quán)過(guò)濾器
授權(quán)過(guò)濾器用于實(shí)現(xiàn)IAuthorizationFilter接口和做出關(guān)于是否執(zhí)行操作方法(如執(zhí)行身份驗(yàn)證或驗(yàn)證請(qǐng)求的屬性)的安全策略。AuthorizeAttribute類繼承了IAuthorizationFilter接口,是授權(quán)過(guò)濾器的示例。授權(quán)過(guò)濾器在任何其他過(guò)濾器之前運(yùn)行。
如果要自定義授權(quán)過(guò)濾器,只需要定義一個(gè)類繼承自AuthorizeAttribute類,然后重寫AuthorizeAttribute類里面的方法即可。
二、示例
下面根據(jù)一個(gè)具體的案例來(lái)講解如何使用自定義過(guò)濾器
1、添加對(duì)應(yīng)實(shí)體類
User實(shí)體類代碼如下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace MVCCustomerFilterDemo.Models { public class User { public int Id { get; set; } public string UserName { get; set; } public int RoleId { get; set; } } }
Role實(shí)體類代碼如下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace MVCCustomerFilterDemo.Models { public class Role { public int Id { get; set; } public string RoleName { get; set; } public string Description { get; set; } } }
RoleWithControllerAction實(shí)體類代碼如下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace MVCCustomerFilterDemo.Models { public class RoleWithControllerAction { public int Id { get; set; } public string ControllerName { get; set; } public string ActionName { get; set; } public string RoleIds { get; set; } } }
用于展示登錄視圖的登錄用戶實(shí)體類LogOnViewModel代碼如下:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Web; namespace MVCCustomerFilterDemo.Models { // <summary> /// 用戶登錄類 /// </summary> public class LogOnViewModel { /// <summary> /// 用戶名 /// </summary> [DisplayName("用戶名")] public string UserName { get; set; } /// <summary> /// 密碼 /// </summary> [DisplayName("密碼")] public string Password { get; set; } /// <summary> /// 記住我 /// </summary> [DisplayName("記住我")] public bool RememberMe { get; set; } } }
2、添加測(cè)試數(shù)據(jù)
在程序中模擬數(shù)據(jù)庫(kù)中的數(shù)據(jù),實(shí)際使用中要去數(shù)據(jù)庫(kù)查詢,代碼如下:
using MVCCustomerFilterDemo.Models; using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace MVCCustomerFilterDemo.DataBase { /// <summary> /// 測(cè)試數(shù)據(jù)(實(shí)際項(xiàng)目中,這些數(shù)據(jù)應(yīng)該從數(shù)據(jù)庫(kù)拿) /// </summary> public class SampleData { public static List<User> users; public static List<Role> roles; public static List<RoleWithControllerAction> roleWithControllerAndAction; static SampleData() { // 初始化用戶 users = new List<User>() { new User(){ Id=1, UserName="jxl", RoleId=1}, new User(){ Id=2, UserName ="senior1", RoleId=2}, new User(){ Id=3, UserName ="senior2", RoleId=2}, new User(){ Id=5, UserName="junior1", RoleId=3}, new User(){ Id=6, UserName="junior2", RoleId=3}, new User(){ Id=6, UserName="junior3", RoleId=3} }; // 初始化角色 roles = new List<Role>() { new Role() { Id=1, RoleName="管理員", Description="管理員角色"}, new Role() { Id=2, RoleName="高級(jí)會(huì)員", Description="高級(jí)會(huì)員角色"}, new Role() { Id=3, RoleName="初級(jí)會(huì)員", Description="初級(jí)會(huì)員角色"} }; // 初始化角色控制器和Action對(duì)應(yīng)類 roleWithControllerAndAction = new List<RoleWithControllerAction>() { new RoleWithControllerAction(){ Id=1, ControllerName="AuthFilters", ActionName="AdminUser", RoleIds="1"}, new RoleWithControllerAction(){ Id=2, ControllerName="AuthFilters", ActionName="SeniorUser",RoleIds="1,2"}, new RoleWithControllerAction(){ Id=3, ControllerName="AuthFilters", ActionName="JuniorUser",RoleIds="1,2,3"}, new RoleWithControllerAction(){ Id=3, ControllerName="AuthFilters", ActionName="Welcome",RoleIds="1,2"}, new RoleWithControllerAction(){ Id=4, ControllerName="ActionFilters", ActionName="Index", RoleIds="2,3"}, new RoleWithControllerAction(){ Id=4, ControllerName="ActionPremisFilters", ActionName="Index", RoleIds="2,3"} }; } } }
3、新建繼承類
新建一個(gè)UserAuthorize類,繼承自AuthorizeAttribute類,然后F12轉(zhuǎn)到定義查看AuthorizeAttribute代碼,代碼如下:
#region 程序集 System.Web.Mvc, Version=5.2.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 // E:\Practice\過(guò)濾器\自定義權(quán)限過(guò)濾器\MVCCustomerFilterDemo\packages\Microsoft.AspNet.Mvc.5.2.4\lib\net45\System.Web.Mvc.dll #endregion namespace System.Web.Mvc { // // 摘要: // 指定對(duì)控制器或操作方法的訪問(wèn)只限于滿足授權(quán)要求的用戶。 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)] public class AuthorizeAttribute : FilterAttribute, IAuthorizationFilter { // // 摘要: // 初始化 System.Web.Mvc.AuthorizeAttribute 類的新實(shí)例。 public AuthorizeAttribute(); // // 摘要: // 獲取或設(shè)置有權(quán)訪問(wèn)控制器或操作方法的用戶角色。 // // 返回結(jié)果: // 有權(quán)訪問(wèn)控制器或操作方法的用戶角色。 public string Roles { get; set; } // // 摘要: // 獲取此特性的唯一標(biāo)識(shí)符。 // // 返回結(jié)果: // 此特性的唯一標(biāo)識(shí)符。 public override object TypeId { get; } // // 摘要: // 獲取或設(shè)置有權(quán)訪問(wèn)控制器或操作方法的用戶。 // // 返回結(jié)果: // 有權(quán)訪問(wèn)控制器或操作方法的用戶。 public string Users { get; set; } // // 摘要: // 在過(guò)程請(qǐng)求授權(quán)時(shí)調(diào)用。 // // 參數(shù): // filterContext: // 篩選器上下文,它封裝有關(guān)使用 System.Web.Mvc.AuthorizeAttribute 的信息。 // // 異常: // T:System.ArgumentNullException: // filterContext 參數(shù)為 null。 public virtual void OnAuthorization(AuthorizationContext filterContext); // // 摘要: // 重寫時(shí),提供一個(gè)入口點(diǎn)用于進(jìn)行自定義授權(quán)檢查。 // // 參數(shù): // httpContext: // HTTP 上下文,它封裝有關(guān)單個(gè) HTTP 請(qǐng)求的所有 HTTP 特定的信息。 // // 返回結(jié)果: // 如果用戶已經(jīng)過(guò)授權(quán),則為 true;否則為 false。 // // 異常: // T:System.ArgumentNullException: // httpContext 參數(shù)為 null。 protected virtual bool AuthorizeCore(HttpContextBase httpContext); // // 摘要: // 處理未能授權(quán)的 HTTP 請(qǐng)求。 // // 參數(shù): // filterContext: // 封裝有關(guān)使用 System.Web.Mvc.AuthorizeAttribute 的信息。filterContext 對(duì)象包括控制器、HTTP 上下文、請(qǐng)求上下文、操作結(jié)果和路由數(shù)據(jù)。 protected virtual void HandleUnauthorizedRequest(AuthorizationContext filterContext); // // 摘要: // 在緩存模塊請(qǐng)求授權(quán)時(shí)調(diào)用。 // // 參數(shù): // httpContext: // HTTP 上下文,它封裝有關(guān)單個(gè) HTTP 請(qǐng)求的所有 HTTP 特定的信息。 // // 返回結(jié)果: // 對(duì)驗(yàn)證狀態(tài)的引用。 // // 異常: // T:System.ArgumentNullException: // httpContext 參數(shù)為 null。 protected virtual HttpValidationStatus OnCacheAuthorization(HttpContextBase httpContext); } }
從AuthorizeAttribute的源代碼中可以看出:里面定義了Users和Roles兩個(gè)屬性,只需要給這兩個(gè)屬性賦值,就可以控制用戶或角色訪問(wèn)了。要實(shí)現(xiàn)自定義的驗(yàn)證只需要重寫OnAuthorization和AuthorizeCore方法。所以,UserAuthorize類代碼如下:
using MVCCustomerFilterDemo.DataBase; using MVCCustomerFilterDemo.Models; using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace MVCCustomerFilterDemo.Extensions { public class UserAuthorize : AuthorizeAttribute { /// <summary> /// 授權(quán)失敗時(shí)呈現(xiàn)的視圖 /// </summary> public string AuthorizationFailView { get; set; } /// <summary> /// 請(qǐng)求授權(quán)時(shí)執(zhí)行 /// </summary> public override void OnAuthorization(AuthorizationContext filterContext) { // 判斷是否已經(jīng)驗(yàn)證用戶 if (!filterContext.HttpContext.User.Identity.IsAuthenticated) { // 如果沒(méi)有驗(yàn)證則跳轉(zhuǎn)到LogOn頁(yè)面 filterContext.HttpContext.Response.Redirect("/Account/LogOn"); } //獲得url請(qǐng)求里的controller和action: string strControllerName = filterContext.RouteData.Values["controller"].ToString().ToLower(); string strActionName = filterContext.RouteData.Values["action"].ToString().ToLower(); //根據(jù)請(qǐng)求過(guò)來(lái)的controller和action去查詢可以被哪些角色操作: Models.RoleWithControllerAction roleWithControllerAction = SampleData.roleWithControllerAndAction.Find(r => r.ControllerName.ToLower() == strControllerName && r.ActionName.ToLower() == strActionName); if (roleWithControllerAction != null) { //有權(quán)限操作當(dāng)前控制器和Action的角色id this.Roles = roleWithControllerAction.RoleIds; } base.OnAuthorization(filterContext); } /// <summary> /// 自定義授權(quán)檢查(返回False則授權(quán)失?。? /// </summary> protected override bool AuthorizeCore(HttpContextBase httpContext) { if (httpContext.User.Identity.IsAuthenticated) { //當(dāng)前登錄用戶的用戶名 string userName = httpContext.User.Identity.Name; //當(dāng)前登錄用戶對(duì)象 User user = SampleData.users.Find(u => u.UserName == userName); if (user != null) { //當(dāng)前登錄用戶的角色 Role role = SampleData.roles.Find(r => r.Id == user.RoleId); foreach (string roleid in Roles.Split(',')) { if (role.Id.ToString() == roleid) return true; } return false; } else return false; } else { //進(jìn)入HandleUnauthorizedRequest return false; } } /// <summary> /// 處理授權(quán)失敗的HTTP請(qǐng)求 /// </summary> protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { filterContext.Result = new ViewResult { ViewName = AuthorizationFailView }; } } }
4、添加Account控制器
Account控制器里面的LogOn方法用來(lái)顯示登陸界面,控制器代碼如下:
using MVCCustomerFilterDemo.Models; using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Security; namespace MVCCustomerFilterDemo.Controllers { public class AccountController : Controller { // GET: Account public ActionResult Index() { return View(); } /// <summary> /// 顯示登錄視圖 /// </summary> /// <returns></returns> public ActionResult LogOn() { LogOnViewModel model = new LogOnViewModel(); return View(model); } /// <summary> /// 處理用戶點(diǎn)擊登錄提交回發(fā)的表單 /// </summary> /// <param name="model"></param> /// <returns></returns> [HttpPost] public ActionResult LogOn(LogOnViewModel model) { //只要輸入的用戶名和密碼一樣就過(guò) if (model.UserName.Trim() == model.Password.Trim()) { // 判斷是否勾選了記住我 if (model.RememberMe) { //2880分鐘有效期的cookie FormsAuthentication.SetAuthCookie(model.UserName, true); } else { //會(huì)話cookie FormsAuthentication.SetAuthCookie(model.UserName, false); } // 跳轉(zhuǎn)到AuthFilters控制器的Welcome方法 return RedirectToAction("Welcome", "AuthFilters"); } else { return View(model); } } /// <summary> /// 注銷 /// </summary> /// <returns></returns> public ActionResult LogOut() { Session.Abandon(); FormsAuthentication.SignOut(); return RedirectToAction("LogOn"); } } }
LogOn方法對(duì)應(yīng)的視圖頁(yè)面代碼如下:
@model MVCCustomerFilterDemo.Models.LogOnViewModel @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>LogOn</title> </head> <body> @using (Html.BeginForm()) { @Html.AntiForgeryToken() <div class="form-horizontal"> <h4>登錄</h4> <hr /> @Html.ValidationSummary(true) <div class="form-group"> @Html.LabelFor(model => model.UserName, new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.UserName) @Html.ValidationMessageFor(model => model.UserName) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.Password, new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Password) @Html.ValidationMessageFor(model => model.Password) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.RememberMe, new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.RememberMe) @Html.ValidationMessageFor(model => model.RememberMe) </div> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <input type="submit" value="登錄" class="btn btn-default" /> </div> </div> </div> } </body> </html>
5、修改配置文件
修改配置文件,定義權(quán)限驗(yàn)證失敗時(shí)跳轉(zhuǎn)的頁(yè)面,代碼如下:
<!--配置登錄頁(yè)面--> <authentication mode="Forms"> <forms loginUrl="~/Account/LogOn" timeout="2880" /> </authentication>
6、添加授權(quán)控制器
添加AuthFilters控制器,代碼如下:
using MVCCustomerFilterDemo.Extensions; using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace MVCCustomerFilterDemo.Controllers { public class AuthFiltersController : Controller { // GET: AuthFilters public ActionResult Index() { return View(); } /// <summary> /// 使用自定義的授權(quán)驗(yàn)證,登錄成功就可以訪問(wèn) /// </summary> /// <returns></returns> [Authorize] public ActionResult Welcome() { return View(); } [UserAuthorize(AuthorizationFailView = "Error")] public ActionResult AdminUser() { ViewBag.Message = "管理員頁(yè)面"; return View("Welcome"); } /// <summary> /// 會(huì)員頁(yè)面(管理員、會(huì)員都可訪問(wèn)) /// </summary> /// <returns></returns> [Authorize] [UserAuthorize(AuthorizationFailView = "Error")] public ActionResult SeniorUser() { ViewBag.Message = "高級(jí)會(huì)員頁(yè)面"; return View("Welcome"); } /// <summary> /// 游客頁(yè)面(管理員、會(huì)員、游客都可訪問(wèn)) /// </summary> /// <returns></returns> [Authorize] [UserAuthorize(AuthorizationFailView = "Error")] public ActionResult JuniorUser() { ViewBag.Message = "初級(jí)會(huì)員頁(yè)面"; return View("Welcome"); } } }
三、測(cè)試
測(cè)試Welcome
Welcome這個(gè)Action使用了默認(rèn)的授權(quán)驗(yàn)證,只要登錄成功就能訪問(wèn)。
URL地址欄里面輸入:http://localhost:****/AuthFilters/Welcome,會(huì)跳轉(zhuǎn)到登錄頁(yè)面,如圖所示:
然后輸入相同的用戶名和密碼,點(diǎn)擊登錄,會(huì)顯示W(wǎng)elcome對(duì)應(yīng)的頁(yè)面:
在看一下SampleData中,角色為1,2的也可以訪問(wèn)Welcome方法,用角色1訪問(wèn)Welcome:
點(diǎn)擊登錄:
從上面的截圖中看出:senior1登錄成功了,senior1是角色2,證明角色1、2可以訪問(wèn)Welcome方法。在使用junior2登錄名訪問(wèn)Welcome方法:
由于junior2的角色是3,而角色3沒(méi)有訪問(wèn)Welcome方法的權(quán)限,所以會(huì)跳轉(zhuǎn)到Error頁(yè)面:
四、總結(jié)
Welcome這個(gè)Action使用了默認(rèn)的授權(quán)驗(yàn)證,只要登陸成功就可以訪問(wèn)。其他幾個(gè)Action上都標(biāo)注了自定義的UserAuthorize,并沒(méi)有標(biāo)注Users="....",Roles=".....",因?yàn)檫@樣在Action上寫死用戶或者角色控制權(quán)限顯然是不可行的,用戶和角色的對(duì)應(yīng)以及不同的角色可以操作的Action應(yīng)該是從數(shù)據(jù)庫(kù)里取出來(lái)的。為了演示就在SampleData類里初始化了一些用戶和角色信息,根據(jù)SampleData類的定義,很明顯jxl擁有1號(hào)管理員角色,可以訪問(wèn)AuthFilters這個(gè)控制器下的所有Action;senior1、senior2擁有2號(hào)高級(jí)會(huì)員的角色,可以訪問(wèn)AuthFilters這個(gè)控制器下除了AdminUser之外的Action等等。
再次登陸下,就發(fā)現(xiàn)擁有高級(jí)會(huì)員角色的用戶senior1是不可以訪問(wèn)AdminUser這個(gè)Action,會(huì)被帶到AuthorizationFailView屬性指定的Error視圖。
GitHub代碼地址:https://github.com/jxl1024/MVCCustomerFilterDemo
到此這篇關(guān)于ASP.NET MVC自定義授權(quán)過(guò)濾器的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
如何在ASP.NET Core 的任意類中注入Configuration
這篇文章主要介紹了如何在 ASP.NET Core 的任意類中注入Configuration ,幫助大家更好的理解和學(xué)習(xí)使用.net技術(shù),感興趣的朋友可以了解下2021-04-04asp.net mvc signalr簡(jiǎn)單聊天室制作過(guò)程分析
這篇文章主要為大家分析了asp.net mvc signalr簡(jiǎn)單聊天室制作過(guò)程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09asp.net下利用JS實(shí)現(xiàn)對(duì)后臺(tái)CS代碼的調(diào)用方法
asp.net下利用JS實(shí)現(xiàn)對(duì)后臺(tái)CS代碼的調(diào)用方法...2007-04-04前臺(tái)JS(jquery ajax)調(diào)用后臺(tái)方法實(shí)現(xiàn)無(wú)刷新級(jí)聯(lián)菜單示例
前臺(tái)用AJAX直接調(diào)用后臺(tái)方法,老有人發(fā)帖提問(wèn),沒(méi)事做個(gè)示例詳細(xì)介紹一下,感興趣的朋友可以參考下2013-01-01ASP.NET Core依賴注入系列教程之控制反轉(zhuǎn)(IoC)
這篇文章主要給大家介紹了關(guān)于ASP.NET Core依賴注入系列教程之控制反轉(zhuǎn)(IoC)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-11-11關(guān)于vs2005、vs2008和vs2010項(xiàng)目互轉(zhuǎn)的總結(jié)
有做.net的程序員和朋友曾經(jīng)問(wèn)過(guò)我,關(guān)于vs2005和vs2008、vs2008和vs2010、vs2005和vs2010項(xiàng)目互轉(zhuǎn)的問(wèn)題,特整理下分享給大家2012-04-04.NET?實(shí)現(xiàn)啟動(dòng)時(shí)重定向程序運(yùn)行路徑及?Windows?服務(wù)運(yùn)行模式部署的方法
這篇文章主要介紹了.NET?實(shí)現(xiàn)啟動(dòng)時(shí)重定向程序運(yùn)行路徑及?Windows?服務(wù)運(yùn)行模式部署,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-09-09.NET 資源文件resx、Resources詳細(xì)說(shuō)明
和大家講一下.net對(duì)資源文件的使用做一下說(shuō)明,希望本文對(duì)你有所幫助。2010-03-03