我正在尝试将此路由逻辑连接到我的ASP MVC应用程序中。
为了简化安全性,我想让所有传递的URL在控制器名称之前都有 project id。
要求如下:
website.com/Account/Login
网址示例:
http://localhost:36923/112233/DataTableRows?id=P8dFd9o8DEitJpak6lGAbA
如果用户确实可以访问项目ID 112233
,则会调用正确的控制器/操作。如果没有,下面的操作过滤器会正确地将用户重定向到错误页面。到目前为止,这是有效的。
问题是缺少项目ID或用户是否无权访问指定的项目。重定向到Account/Login
会产生404错误。
这是我创建的自定义路线:
public sealed class ProjectAttributeRoute : Route
{
public ProjectAttributeRoute(string url)
: base(url, new MvcRouteHandler())
{
}
public override RouteData GetRouteData(HttpContextBase httpContext)
{
var r = base.GetRouteData(httpContext);
//No project id provided so redirect to login page.
if (r == null)
{
r = new RouteData(this, this.RouteHandler);
r.Values.Add("controller", "Account");
r.Values.Add("action", "Login");
}
return r;
}
}
我的路线配置:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapCustomRoutes("ProjectRoute", "
{project}/{controller}/{action}",
defaults: new { action = "Index" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Portal", action = "Index", id =
UrlParameter.Optional }
);
routes.MapRoute(
name: "LoginRoute",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Account", action = "Login", id = UrlParameter.Optional }
);
}
public static class RouteConfigExtensions
{
public static void MapCustomRoutes(this RouteCollection routes, string name, string url, object defaults = null, object constraints = null)
{
routes.Add(name, new ProjectAttributeRoute(url)
{
Defaults = new RouteValueDictionary(defaults),
Constraints = new RouteValueDictionary(constraints),
DataTokens = new RouteValueDictionary()
});
}
}
实际验证用户是否有权访问URL中传递的项目的操作过滤器:
public class ProjectAccessFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var controller = filterContext.Controller as BaseApiController;
//if no project provided in URL. TODO: Make an exception of /Account/Login
if (!filterContext.RequestContext.RouteData.Values.ContainsKey("project"))
{
UrlHelper urlHelper = new UrlHelper(filterContext.RequestContext);
filterContext.HttpContext.GetOwinContext().Authentication.SignOut();
filterContext.Result = new RedirectResult(urlHelper.Action("Login", "Account"));
return;
}
var urlProjectId = filterContext.RequestContext.RouteData.Values["project"].ToString();
List<ProjectModel> userProjects = new List<ProjectModel>();
//the data layer which is called in GetProjectsFromCurrentUser is async, so I have to do this...
var t = Task.Run(async () =>
{
return (await controller.GetProjectsFromCurrentUser()).ToList();
});
userProjects = t.Result;
if (!userProjects.Any(x => x.Id == urlProjectId))
{
UnhandledExceptionViewModel viewModel = new UnhandledExceptionViewModel();
viewModel.ExceptionMessage = $"User has no access to project '{urlProjectId}'";
var result = new ViewResult
{
ViewData = new ViewDataDictionary(viewModel),
ViewName = "Error"
};
filterContext.Result = result;
}
}
}
任何明显错误的路线配置?
答案 0 :(得分:0)
请检查您的自定义路由过滤应该注册的Global.asax.cs文件Application_Start()方法
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
答案 1 :(得分:0)
我最终使用了这条路线配置:
Get
使用自定义约束:
routes.MapRoute(
name: "NoProjectRoute",
url: "{controller}/{action}",
defaults: new { action = "Index" },
constraints: new { controller = new NoProjectRouteConstraint() }
);
routes.MapCustomRoutes("ProjectRoute",
"{project}/{controller}/{action}",
defaults: new { action = "Index" }
);
routes.MapRoute(
name: "Default",
url: "{project}/{controller}/{action}",
defaults: new { controller = "Portal", action = "Index" }
);