Asp.net-Mvc
我將如何編寫一個 ActionFilter 來確保每個 Post 操作都使用 AntiForgeryTokens?
我想
AntiForgeryTokens在每個 HttpPost 操作上使用一個 ActionFilter,該控制器位於一個名為ControllerBase該控制器的控制器中,每個其他控制器都繼承自該控制器。我想通過創建一個繼承自它的 ActionFilter 來做到這一點,
ValidateAntiForgeryToken它接受一個參數來告訴它要將自身應用於哪些 HTTP 動詞。然後我想應用該過濾器ControllerBase以確保AntiForgeryToken檢查整個站點上的每個 POST 操作。我正在考慮使用這個解決方案,但是
AuthorizationContext Constructor (ControllerContext)是一個過時的建構子,我不確定如何使用推薦的AuthorizationContext(ControllerContext controllerContext, ActionDescriptor actionDescriptor).- 預設情況下,它似乎沒有使用 AntiForgeryToken,因為我收到以下錯誤:
A required anti-forgery token was not supplied or was invalid在每次發布操作之後。
[HttpPost]我應該如何重寫我的 ActionFilter 以滿足目前的非過時標準並在每個動詞上正確使用防偽標記?我自己是否必須在每種形式中都包含防偽令牌(我想我會這樣做)?(而不是自動生成 - 不要笑,我很好奇) **更新:**正如評論中指出的那樣;是的,這必須對每個表格進行。
這是我的 ControllerBase 中的程式碼供參考:
[UseAntiForgeryTokenOnPostByDefault] public class ControllerBase : Controller { [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] public class BypassAntiForgeryTokenAttribute : ActionFilterAttribute { } [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] public class UseAntiForgeryTokenOnPostByDefault : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext filterContext) { if (ShouldValidateAntiForgeryTokenManually(filterContext)) { var authorizationContext = new AuthorizationContext(filterContext.Controller.ControllerContext); //Use the authorization of the anti forgery token, //which can't be inhereted from because it is sealed new ValidateAntiForgeryTokenAttribute().OnAuthorization(authorizationContext); } base.OnActionExecuting(filterContext); } /// <summary> /// We should validate the anti forgery token manually if the following criteria are met: /// 1. The http method must be POST /// 2. There is not an existing [ValidateAntiForgeryToken] attribute on the action /// 3. There is no [BypassAntiForgeryToken] attribute on the action /// </summary> private static bool ShouldValidateAntiForgeryTokenManually(ActionExecutingContext filterContext) { var httpMethod = filterContext.HttpContext.Request.HttpMethod; //1. The http method must be POST if (httpMethod != "POST") return false; // 2. There is not an existing anti forgery token attribute on the action var antiForgeryAttributes = filterContext.ActionDescriptor.GetCustomAttributes(typeof (ValidateAntiForgeryTokenAttribute), false); if (antiForgeryAttributes.Length > 0) return false; // 3. There is no [BypassAntiForgeryToken] attribute on the action var ignoreAntiForgeryAttributes = filterContext.ActionDescriptor.GetCustomAttributes(typeof (BypassAntiForgeryTokenAttribute), false); if (ignoreAntiForgeryAttributes.Length > 0) return false; return true; } } }
您不需要實例化任何方法
AuthorizationContext或呼叫該OnAuthorization方法,只需:if (ShouldValidateAntiForgeryTokenManually(filterContext)) { AntiForgery.Validate(filterContext.HttpContext, null); }
我使用了以下方法:
public class SkipCSRFCheckAttribute : Attribute { } public class AntiForgeryTokenFilter : IAuthorizationFilter { public void OnAuthorization(AuthorizationContext filterContext) { if (IsHttpPostRequest(filterContext) && !SkipCsrfCheck(filterContext)) AntiForgery.Validate(); } private static bool IsHttpPostRequest(AuthorizationContext filterContext) { return filterContext.RequestContext.HttpContext.Request.HttpMethod == HttpMethod.Post.ToString(); } private static bool SkipCsrfCheck(AuthorizationContext filterContext) { return filterContext.ActionDescriptor.GetCustomAttributes(typeof (SkipCSRFCheck), false).Any(); } }這使我們能夠使用 SkipCSRFCheck 屬性逐個禁用它,然後在 Application_Start 中將其註冊為全域過濾器:
GlobalFilters.Filters.Add(new AntiForgeryTokenFilter());