ASP.NET Core RazorPages中,我們可以在頁面模型基類中過載OnPageHandlerExecuting方法。
下面的例子中,BaseModel繼承自 PageModel,是所有頁面模型的基類。
推薦方案:
在BaseModel.cs中,過載OnPageHandlerExecuting方法(看下面程式碼中的註釋):
public override void OnPageHandlerExecuting(PageHandlerExecutingContext context) { base.OnPageHandlerExecuting(context); if (IsPostBack) { // 回發請求時,檢索請求資料或者Cookie,來驗證當前訪問是否有效。請求無效時,彈出錯誤提示,不再執行Page_Load和回發事件。 if (!String.IsNullOrEmpty(Request.Query["error"])) { ShowNotify("身份驗證失敗!"); // Setting Result to a non-null value inside a page filter will short-circuit the page and any remaining page filters. // 設定context.Result=UIHelper.Result(),可以中斷頁面繼續執行(跳過接下來的 Page_Load 和回發事件)。 context.Result = UIHelper.Result(); } } }
微軟官方文件:https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.filters.pagehandlerexecutingcontext?view=aspnetcore-8.0
上述文件中,在解釋 Result 屬性時,專門提到了這個事情:
在頁面過濾器內將 Result 設定為非空值將使該頁面和任何剩餘的頁面過濾器短路。
延伸閱讀
===================
其實上述方案在6年前釋出 AppBoxCore 時已經存在了,只不過在 AppBoxCore 中做的更加工程化,也更加清晰。
當前的需求是要求有些頁面需要進行身份驗證,而一些公開的頁面不需要身份驗證。
1. 我們首先定義 CheckPowerAttribute 過濾器。
namespace AppBoxCore.Dapper { /// <summary> /// AppBoxCore自定義許可權驗證過濾器 /// </summary> public class CheckPowerAttribute : ResultFilterAttribute { /// <summary> /// 許可權名稱 /// </summary> public string Name { get; set; } public override void OnResultExecuting(ResultExecutingContext filterContext) { HttpContext context = filterContext.HttpContext; // 許可權驗證不透過 if (!String.IsNullOrEmpty(Name) && !BaseModel.CheckPower(context, Name)) { if (context.Request.Method == "GET") { BaseModel.CheckPowerFailWithPage(context); // -修正越權訪問頁面時會報錯[伺服器無法在傳送 HTTP 標頭之後追加標頭](龍濤軟體-9374)。 filterContext.Result = new EmptyResult(); } else if (context.Request.Method == "POST") { BaseModel.CheckPowerFailWithAlert(); filterContext.Result = UIHelper.Result(); } } } } }
參考文件:http://stackoverflow.com/questions/9837180/how-to-skip-action-execution-from-an-actionfilter
這個文件也相關有參考價值,當時遇到一個報錯:
伺服器無法在傳送 HTTP 標頭之後追加標頭
如果需要在 GET 請求中結束當前請求,也需要設定 new EmptyResult()。
2. 然後需要進行身份驗證的頁面,在頁面模型上定義此屬性即可。
比如 Admin 目錄下的 Config 頁面:
[CheckPower(Name = "CoreConfigView")] public class ConfigModel : BaseAdminModel { ... }