開發過MVC的人都知道,MVC是三個單詞的縮寫,分別爲: 模型(Model),視圖(View)和控制Controller)。 MVC模式的目的就是實現Web系統的職能分工。 Model層實現系統中的業務邏輯。 View層用於與用戶的交互。 Controller層是Model與View之間溝通的橋樑,它可以分派用戶的請求並選擇恰當的視圖以用於顯示,同時它也可以解釋用戶的輸入並將它們映射爲模型層可執行的操作。
我們的權限驗證就添加在控制(Controller)層,這是必然的。驗證的機制就是,每一次客戶端對於Controller裏邊的Action的請求之前,都會先驗證用戶的身份,也就是說,用戶每一次對於數據的請求,都會驗證當前用戶是否有使用該數據的權限。
本文所介紹的MVC身份驗證大致分爲以下四個部分:
AuthenticationAsserts 授權驗證的相關斷言
AuthorizationFilter 驗證過濾器的構造函數
ControllerActionInvoker 自定義ControllerActionInvoker
DefaultControllerFactory 自定義的ControllerFactory,可以通過ControllerFactory向Controller中植入相關的ActionInvoker
下邊先從授權驗證的相關斷言說起,驗證斷言的作用是:確定用戶的請求是否需要驗證和確認是否以驗證過。它主要包含以下幾個方法:精確的權驗驗證,確定系統是否需要驗證,確定用戶是否已經通過驗證,以及判斷用戶是否擁有訪問該URL的權限。下邊看看代碼:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using Configuration;
using Membership;
using System.Web;
using User.ServiceImp;
using MVCExtension;
namespace Authorization
{
/// <summary>
/// 授權驗證的相關斷言。
/// </summary>
public class AuthenticationAsserts
{
/// <summary>
/// 確認系統是否需要權限驗證(系統在開發期間,爲了開發調試方便,可以不需要權限驗證,而在開發完成後,套用框架後纔要求驗證)。
/// </summary>
/// <returns>如果需要驗證,則返回True,否則返回False</returns>
public static bool IsRequireAuthenticate()
{
try
{
return bool.Parse(ConfigConstString.Instance.IsSOAVlidate);
}
catch
{
return false;
}
}
/// <summary>
/// 判斷用戶是否已經通過登錄驗證
/// </summary>
/// <param name="controllerContext">Controller的上下文</param>
/// <returns>如果通過驗證,返回True,否則返回False</returns>
public static bool IsAuthenticated(ControllerContext controllerContext)
{
return controllerContext.HttpContext.User.Identity.IsAuthenticated;
}
/// <summary>
/// 判斷Action是否標示爲避免驗證?(AvoidAuthenticateAttribute)
/// </summary>
/// <returns>如果該Action標示爲避免驗證,返回True,否則返回False。</returns>
public static bool IsActionAvoidAuthenticate(ControllerContext Controller, IList<IAuthorizationFilter> filters)
{
bool _ISSecure =false;
foreach (IAuthorizationFilter filer in filters)
{
if (filer is SecureFilterAttribute)
{
SecureFilterAttribute secureFilterAttribute = (SecureFilterAttribute)filer;
_ISSecure = (bool)secureFilterAttribute.ISSecure;
if (_ISSecure) break;
}
else if (filer is ElinkFilterAttribute)
{
string controller = Controller.Controller.ToString();
string id = HttpContext.Current.Request.Params["ElinkID"];
try
{
Guid linkid = id == null ? Guid.NewGuid() : new Guid(id);
_ISSecure =UserGateway.TenantProvider.IsLinkerSecure(controller, linkid,"");
}
catch(Exception e)
{
_ISSecure = false;
}
break;
}
else if(filer is AccurateFilterAttribute)//鏈接授權
{
Identity bi = (Identity)Controller.HttpContext.User.Identity;
int userid = bi.UserID;
HttpRequest httpRequest = new HttpRequest(string.Empty, Controller.HttpContext.Request.Url.ToString(), Controller.HttpContext.Request.QueryString.ToString());
bool result = UserGateway.TenantSecurityProvider.IsSignatureUrlsecure(httpRequest,userid);
_ISSecure = result;
}
}
return _ISSecure;
}
/// <summary>
/// 精確授權驗證
/// </summary>
/// <param name="Controller"></param>
/// <param name="filters"></param>
/// <returns></returns>
public static bool IsAccurateAuthenticate(ControllerContext Controller, IList<IAuthorizationFilter> filters)
{
bool _ISSecure = true;
foreach (IAuthorizationFilter filer in filters)
{
if (filer is AccurateFilterAttribute)//鏈接授權
{
Identity bi = (Identity)Controller.HttpContext.User.Identity;
int userid = bi.UserID;
HttpRequest httpRequest = new HttpRequest(string.Empty, Controller.HttpContext.Request.Url.ToString(), Controller.HttpContext.Request.QueryString.ToString());
bool result = UserGateway.TenantSecurityProvider.IsSignatureUrlsecure(httpRequest,
userid);
_ISSecure = result;
}
}
return _ISSecure;
}
/// <summary>
/// 判斷用戶是否擁有訪問該URL的權限。
/// 用戶是否授權訪問該URL包括兩個部分:
///1.用戶有該URL對應功能的訪問角色;
///2.用戶所在租戶擁有該功能的使用授權。
/// </summary>
/// <param name="url">當前訪問的URL</param>
/// <returns>如果用戶有權訪問該URL,返回true,否則返回False。</returns>
public static bool IsUserHasPermissionAccess(Type controllerType, string actionName)
{
string url=HttpContextGateWay.Instance.GetHttpContext().Request.Url.AbsolutePath;
bool result = MembershipProviderGateWay.Instance.IsFuntionUsableByUrl(url);//||MembershipProviderGateWay.Instance.IsFuntionUsableByUrl(fullActionUrl)
return result;
}
}
}
然後就該是過濾器部分了:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using BI.Common.Model;
using User.ServiceImp;
using Membership;
namespace Authorization
{
partial class BIAuthorizationFilter : IAuthorizationFilter
{
private Type _controllerType;
private string _actionName;
private readonly ControllerContext _controllerContext;
private readonly IList<IAuthorizationFilter> _filters;
/// <summary>
/// 自定義驗證過濾器的構造函數
/// </summary>
/// <param name="controllerType">當前的controllerType</param>
/// <param name="actionName">當前調用的actionName</param>
public BIAuthorizationFilter(IList<IAuthorizationFilter> filters, Type controllerType, string actionName, ControllerContext controllerContext)
{
_controllerType = controllerType;
_actionName = actionName;
_controllerContext = controllerContext;
_filters = filters;
}
public void OnAuthorization(AuthorizationContext filterContext)
{
//權限驗證部分代碼
}
/// <summary>
/// 得到完整Url
/// </summary>
/// <returns></returns>
public string GetCurrentFullUrl(AuthorizationContext context)
{
return string.Format("{0}://{1}{2}", context.HttpContext.Request.Url.Scheme, context.HttpContext.Request.Url.Host, c ontext.HttpContext.Request.RawUrl);
}
private void RedirectToLogin(AuthorizationContext context, string url)
{
context.HttpContext.Response.Redirect(String.Format("{0}?ReturnUrl={1}", FormsAuthentication.LoginUrl, HttpUtility.U rlEncode(url)));
}
}
}
然後就該說說自定義ControllerActionInvoker了。也就是ControllerAction的回調函數:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using BI.Authorization;
namespace BI.Authorization
{
/// <summary>
/// 自定義ControllerActionInvoker
/// </summary>
public class BIControllerActionInvoker:ControllerActionInvoker
{
protected override AuthorizationContext InvokeAuthorizationFilters(ControllerContext controllerContext, IList<IAuthorizationFilter> filters, ActionDescriptor actionDescriptor)
{
//在這裏插入自定義的驗證Filter
if(filters == null)
{
filters = new List<IAuthorizationFilter>();
}
IAuthorizationFilter filter = new BIAuthorizationFilter(filters, actionDescriptor.ControllerDescriptor.ControllerType, actionDescriptor.ActionName, controllerContext);
filters.Insert(0,filter);
return base.InvokeAuthorizationFilters(controllerContext, filters, actionDescriptor);
}
}
}
最後該說說我們的工廠類了:
自定義的ControllerFactory,可以通過ControllerFactory向Controller中植入相關的ActionInvoker
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
namespace BI.Authorization
{
/// <summary>
/// 自定義的ControllerFactory,可以通過ControllerFactory向Controller中植入相關的ActionInvoker
/// </summary>
public class BIDefaultControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
{
requestContext.HttpContext.Response.BufferOutput = true;
IController instance = base.GetControllerInstance(requestContext, controllerType);
if (instance != null && typeof(Controller).IsAssignableFrom(controllerType))
{
Controller controller = (Controller)instance;
//依賴注入
controller.ActionInvoker = new BIControllerActionInvoker();
//controller.
return controller;
}
else
{
return instance;
}
}
}
}
到這裏就把全部的代碼寫在上邊了。
在使用的時候,只需在Global.asax裏邊的Application_Start()裏邊寫入我們在路由裏邊對於我們的方法的註冊就好了:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
ControllerBuilder.Current.SetControllerFactory(new BIDefaultControllerFactory());
RegisterRoutes(RouteTable.Routes);
}
到這個時候,我們在Controller裏邊就不需要打標籤了,默認的就是所有的Action都會進行我們提前設計好的權限驗證了。
public ActionResult Index()
{
ViewData["ReportName"] = "績效考覈進程報表";
ViewData["EncryptionString"] = str;
return View();
}
到這裏就結束了,時間關係,沒有講的很細,不明白的就看代碼吧。