ASP.NET MVC条件路由

本文关键字:路由 条件 MVC NET ASP | 更新日期: 2023-09-27 18:00:25

在我的MVC应用程序中,我的路由定义如下:

        routes.MapRoute(
            "Category_default",
            "{lang}/Category/{categoryid}/{controller}/{action}/{id}",
            new { lang = "en", action = "Index", id = UrlParameter.Optional, categoryid = -1 }
        ).DataTokens.Add("area", "Category");
        routes.MapRoute(
            name: "Default",
            url: "{lang}/{controller}/{action}/{id}",
            defaults: new { controller = "home", action = "index", lang = "en", id = UrlParameter.Optional }
        );

该应用程序运行良好。然而,系统管理员刚刚告诉我,那些无法访问该类别的用户(换句话说,他们在逻辑上与该类别无关)也可以通过切换categoryid参数来查看数据,这并不奇怪,因为我没有在那里进行任何检查。

检查用户是否对此类别拥有权限的有效方法是什么。在系统中,我有一个User.AllowedCategories List的User对象,它包含用户可以访问的所有id的整数值。

类别区域有大约20个控制器(因此有20个视图)。我是否应该对每个视图进行逻辑检查?或者我可以用最少的编码/或者我可以把这个逻辑放在全局范围内吗?

ASP.NET MVC条件路由

您可以通过三种方式实现这一点,

方法1:全局过滤器

在FilterConfig.cs:中

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
   filters.Add(new ValidateUserFilter());
}

在ValidateUserFilter.cs 中

public class ValidateUserFilter : IActionFilter
{
    public void OnActionExecuted(ActionExecutedContext filterContext)
    {
    }
    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
        //Controllers to avoid validation
        if ((new[] { "<<CONTROLLER1>>", "<<CONTROLLER2>>" }).Any(x => x == filterContext.ActionDescriptor.ControllerDescriptor.ControllerName))
        {
            return;
        }
        if (!User.AllowedCategories.Any(x => x == FilterContext.RequestContext.RouteData.Values["id"]))
        {
            //Redirect user to unauthorized page.
            filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary { { "Controller", "<<CONTROLLER_NAME>>" }, { "Action", "<<ACTION_NAME>>" } });
        }
    }
}

方法2:FilterAttribute

public class ValidateControllerAttribute : FilterAttribute, IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationContext filterContext)
    {
        if (!User.AllowedCategories.Any(x => x == filterContext.RequestContext.RouteData.Values["id"]))
        {
            //Redirect user to unauthorized page.
            filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary { { "Controller", "<<CONTROLLER_NAME>>" }, { "Action", "<<ACTION_NAME>>" } });
            //OR, You can redirect to 403 response
            //throw new HttpException((int)System.Net.HttpStatusCode.Forbidden, "You do not have permission to view this page");
        }
    }
}

您必须在每个想要的控制器中添加此属性验证

例如:

[ValidateController]
public class MyControllerController : Controller

方法3:ActionMethodSelectorAttribute

public class ValidateActionAttribute : ActionMethodSelectorAttribute
{
    public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
    {
        if (!User.AllowedCategories.Any(x => x == controllerContext.RequestContext.RouteData.Values["id"]))
        {
            //Redirect user to unauthorized page.
            controllerContext.HttpContext.Response.Clear();
            controllerContext.HttpContext.Response.Redirect("~/<<CONTROLLER_NAME>>/<<ACTION_NAME>>");
            return false;
            //OR, You can redirect to 403 response
            //throw new HttpException((int)System.Net.HttpStatusCode.Forbidden, "You do not have permission to view this page");
            /*OR,
            controllerContext.HttpContext.Response.StatusCode = 403;
            return true;*/
        }
    }
}

你必须在你想要的每个动作中添加这个属性验证

例如:

[ValidateAction]
public ActionResult Index()
{
    return View();
}

如果我做对了,本质上的问题是,未经授权的用户能够访问应用程序的某些部分,而这是不应该的。

您可以在操作方法上使用Authorize属性,也可以在Controller类上使用,这取决于您希望获得授权的区域。如果您的设计允许,如果您不希望重复,也可以考虑创建一个base controller并在其上应用Authorize属性。

现在使用RolesUsers参数指定这些控制器的有效用户

[Authorize(Roles = "Valid Roles", Users = "Valid Users")]

如果默认的Authorize属性不能满足您的需要,您可以始终创建自己的自定义属性进行授权。