ASP.NET MVC自定義授權(quán)過濾器
一、授權(quán)過濾器
授權(quán)過濾器用于實現(xiàn)IAuthorizationFilter接口和做出關(guān)于是否執(zhí)行操作方法(如執(zhí)行身份驗證或驗證請求的屬性)的安全策略。AuthorizeAttribute類繼承了IAuthorizationFilter接口,是授權(quán)過濾器的示例。授權(quán)過濾器在任何其他過濾器之前運行。
如果要自定義授權(quán)過濾器,只需要定義一個類繼承自AuthorizeAttribute類,然后重寫AuthorizeAttribute類里面的方法即可。
二、示例
下面根據(jù)一個具體的案例來講解如何使用自定義過濾器
1、添加對應(yīng)實體類
User實體類代碼如下:
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實體類代碼如下:
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實體類代碼如下:
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; }
}
}用于展示登錄視圖的登錄用戶實體類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、添加測試數(shù)據(jù)
在程序中模擬數(shù)據(jù)庫中的數(shù)據(jù),實際使用中要去數(shù)據(jù)庫查詢,代碼如下:
using MVCCustomerFilterDemo.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace MVCCustomerFilterDemo.DataBase
{
/// <summary>
/// 測試數(shù)據(jù)(實際項目中,這些數(shù)據(jù)應(yīng)該從數(shù)據(jù)庫拿)
/// </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="高級會員", Description="高級會員角色"},
new Role() { Id=3, RoleName="初級會員", Description="初級會員角色"}
};
// 初始化角色控制器和Action對應(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、新建繼承類
新建一個UserAuthorize類,繼承自AuthorizeAttribute類,然后F12轉(zhuǎn)到定義查看AuthorizeAttribute代碼,代碼如下:
#region 程序集 System.Web.Mvc, Version=5.2.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
// E:\Practice\過濾器\自定義權(quán)限過濾器\MVCCustomerFilterDemo\packages\Microsoft.AspNet.Mvc.5.2.4\lib\net45\System.Web.Mvc.dll
#endregion
namespace System.Web.Mvc
{
//
// 摘要:
// 指定對控制器或操作方法的訪問只限于滿足授權(quán)要求的用戶。
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class AuthorizeAttribute : FilterAttribute, IAuthorizationFilter
{
//
// 摘要:
// 初始化 System.Web.Mvc.AuthorizeAttribute 類的新實例。
public AuthorizeAttribute();
//
// 摘要:
// 獲取或設(shè)置有權(quán)訪問控制器或操作方法的用戶角色。
//
// 返回結(jié)果:
// 有權(quán)訪問控制器或操作方法的用戶角色。
public string Roles { get; set; }
//
// 摘要:
// 獲取此特性的唯一標(biāo)識符。
//
// 返回結(jié)果:
// 此特性的唯一標(biāo)識符。
public override object TypeId { get; }
//
// 摘要:
// 獲取或設(shè)置有權(quán)訪問控制器或操作方法的用戶。
//
// 返回結(jié)果:
// 有權(quán)訪問控制器或操作方法的用戶。
public string Users { get; set; }
//
// 摘要:
// 在過程請求授權(quán)時調(diào)用。
//
// 參數(shù):
// filterContext:
// 篩選器上下文,它封裝有關(guān)使用 System.Web.Mvc.AuthorizeAttribute 的信息。
//
// 異常:
// T:System.ArgumentNullException:
// filterContext 參數(shù)為 null。
public virtual void OnAuthorization(AuthorizationContext filterContext);
//
// 摘要:
// 重寫時,提供一個入口點用于進(jìn)行自定義授權(quán)檢查。
//
// 參數(shù):
// httpContext:
// HTTP 上下文,它封裝有關(guān)單個 HTTP 請求的所有 HTTP 特定的信息。
//
// 返回結(jié)果:
// 如果用戶已經(jīng)過授權(quán),則為 true;否則為 false。
//
// 異常:
// T:System.ArgumentNullException:
// httpContext 參數(shù)為 null。
protected virtual bool AuthorizeCore(HttpContextBase httpContext);
//
// 摘要:
// 處理未能授權(quán)的 HTTP 請求。
//
// 參數(shù):
// filterContext:
// 封裝有關(guān)使用 System.Web.Mvc.AuthorizeAttribute 的信息。filterContext 對象包括控制器、HTTP 上下文、請求上下文、操作結(jié)果和路由數(shù)據(jù)。
protected virtual void HandleUnauthorizedRequest(AuthorizationContext filterContext);
//
// 摘要:
// 在緩存模塊請求授權(quán)時調(diào)用。
//
// 參數(shù):
// httpContext:
// HTTP 上下文,它封裝有關(guān)單個 HTTP 請求的所有 HTTP 特定的信息。
//
// 返回結(jié)果:
// 對驗證狀態(tài)的引用。
//
// 異常:
// T:System.ArgumentNullException:
// httpContext 參數(shù)為 null。
protected virtual HttpValidationStatus OnCacheAuthorization(HttpContextBase httpContext);
}
}從AuthorizeAttribute的源代碼中可以看出:里面定義了Users和Roles兩個屬性,只需要給這兩個屬性賦值,就可以控制用戶或角色訪問了。要實現(xià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)失敗時呈現(xiàn)的視圖
/// </summary>
public string AuthorizationFailView { get; set; }
/// <summary>
/// 請求授權(quán)時執(zhí)行
/// </summary>
public override void OnAuthorization(AuthorizationContext filterContext)
{
// 判斷是否已經(jīng)驗證用戶
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
// 如果沒有驗證則跳轉(zhuǎn)到LogOn頁面
filterContext.HttpContext.Response.Redirect("/Account/LogOn");
}
//獲得url請求里的controller和action:
string strControllerName = filterContext.RouteData.Values["controller"].ToString().ToLower();
string strActionName = filterContext.RouteData.Values["action"].ToString().ToLower();
//根據(jù)請求過來的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)前登錄用戶對象
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請求
/// </summary>
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
filterContext.Result = new ViewResult { ViewName = AuthorizationFailView };
}
}
}4、添加Account控制器
Account控制器里面的LogOn方法用來顯示登陸界面,控制器代碼如下:
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>
/// 處理用戶點擊登錄提交回發(fā)的表單
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
[HttpPost]
public ActionResult LogOn(LogOnViewModel model)
{
//只要輸入的用戶名和密碼一樣就過
if (model.UserName.Trim() == model.Password.Trim())
{
// 判斷是否勾選了記住我
if (model.RememberMe)
{
//2880分鐘有效期的cookie
FormsAuthentication.SetAuthCookie(model.UserName, true);
}
else
{
//會話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方法對應(yīng)的視圖頁面代碼如下:
@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)限驗證失敗時跳轉(zhuǎn)的頁面,代碼如下:
<!--配置登錄頁面-->
<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)驗證,登錄成功就可以訪問
/// </summary>
/// <returns></returns>
[Authorize]
public ActionResult Welcome()
{
return View();
}
[UserAuthorize(AuthorizationFailView = "Error")]
public ActionResult AdminUser()
{
ViewBag.Message = "管理員頁面";
return View("Welcome");
}
/// <summary>
/// 會員頁面(管理員、會員都可訪問)
/// </summary>
/// <returns></returns>
[Authorize]
[UserAuthorize(AuthorizationFailView = "Error")]
public ActionResult SeniorUser()
{
ViewBag.Message = "高級會員頁面";
return View("Welcome");
}
/// <summary>
/// 游客頁面(管理員、會員、游客都可訪問)
/// </summary>
/// <returns></returns>
[Authorize]
[UserAuthorize(AuthorizationFailView = "Error")]
public ActionResult JuniorUser()
{
ViewBag.Message = "初級會員頁面";
return View("Welcome");
}
}
}三、測試
測試Welcome
Welcome這個Action使用了默認(rèn)的授權(quán)驗證,只要登錄成功就能訪問。
URL地址欄里面輸入:http://localhost:****/AuthFilters/Welcome,會跳轉(zhuǎn)到登錄頁面,如圖所示:

然后輸入相同的用戶名和密碼,點擊登錄,會顯示W(wǎng)elcome對應(yīng)的頁面:

在看一下SampleData中,角色為1,2的也可以訪問Welcome方法,用角色1訪問Welcome:

點擊登錄:

從上面的截圖中看出:senior1登錄成功了,senior1是角色2,證明角色1、2可以訪問Welcome方法。在使用junior2登錄名訪問Welcome方法:

由于junior2的角色是3,而角色3沒有訪問Welcome方法的權(quán)限,所以會跳轉(zhuǎn)到Error頁面:

四、總結(jié)
Welcome這個Action使用了默認(rèn)的授權(quán)驗證,只要登陸成功就可以訪問。其他幾個Action上都標(biāo)注了自定義的UserAuthorize,并沒有標(biāo)注Users="....",Roles=".....",因為這樣在Action上寫死用戶或者角色控制權(quán)限顯然是不可行的,用戶和角色的對應(yīng)以及不同的角色可以操作的Action應(yīng)該是從數(shù)據(jù)庫里取出來的。為了演示就在SampleData類里初始化了一些用戶和角色信息,根據(jù)SampleData類的定義,很明顯jxl擁有1號管理員角色,可以訪問AuthFilters這個控制器下的所有Action;senior1、senior2擁有2號高級會員的角色,可以訪問AuthFilters這個控制器下除了AdminUser之外的Action等等。
再次登陸下,就發(fā)現(xiàn)擁有高級會員角色的用戶senior1是不可以訪問AdminUser這個Action,會被帶到AuthorizationFailView屬性指定的Error視圖。
GitHub代碼地址:https://github.com/jxl1024/MVCCustomerFilterDemo
到此這篇關(guān)于ASP.NET MVC自定義授權(quán)過濾器的文章就介紹到這了。希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
在ASP.NET使用JavaScript顯示信息提示窗口實現(xiàn)原理及代碼
在ASP.NET使用JavaScript顯示信息窗口,感興趣的朋友可以了解一下,本文將介紹詳細(xì)的操作步驟,希望對你的JavaScript知識鞏固有所幫助2013-01-01
.net core 靜態(tài)類獲取appsettings的方法
這篇文章主要介紹了.net core 靜態(tài)類獲取appsettings的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06
asp.net利用HttpModule實現(xiàn)防sql注入
關(guān)于sql注入,已經(jīng)被很多人討論過了。這篇沒有新意功能也不夠通用,nnd,不想引起口水,就是覺得簡單而且思路有參考性才貼出來。2009-12-12
ASP.NET中Web.config文件的層次關(guān)系詳細(xì)介紹
Web.config 是一個基于 XML 的配置文件,該文件的作用是對應(yīng)用程序進(jìn)行配置,下面為大家介紹下ASP.NET中Web.config文件的層次關(guān)系2014-01-01
ASP.NET MVC+EF框架+EasyUI實現(xiàn)權(quán)限管系列
在學(xué)習(xí)MVC之前,我們有必要知道這些知識點(自動屬性,隱式類型var,對象初始化器和集合初始化器,匿名類,擴(kuò)展方法,Lambda表達(dá)式),如果你還不知道的話就請看我下面的簡單的介紹,看下面我建立的項目的初步圖像,然后下篇我們開始簡單的介紹。2014-11-11

