MVC5中如何基于returnUrl获取控制器与Action名称?
问题描述
我正在开发一个MVC5应用,需要实现returnUrl功能,当前的Login Action代码如下:
[AllowAnonymous] public ActionResult Login(string returnUrl) { ViewBag.ReturnUrl = returnUrl; var model = new LoginViewModel(); return View(model); }
目前功能运行正常,用户登录后会跳转到returnUrl指定的路径。但当returnUrl无效或用户没有对应路径的权限时,我希望将用户导航至仪表盘。由于同时使用了常规路由与属性路由,无法通过拆分URL来验证Action的有效性,请问有没有方法基于returnUrl获取对应的控制器名称与Action名称?
解决方案
嘿,这个场景我之前处理过,MVC5其实自带了能兼容常规路由和属性路由的URL解析机制,不用手动拆分URL就能拿到控制器和Action名称,给你分享个靠谱的实现方式:
1. 写个路由解析的辅助工具类
先封装一个静态方法,利用框架的路由上下文来解析URL,不管是哪种路由规则都能识别:
public static class RouteHelper { public static (string ControllerName, string ActionName) GetControllerAndActionFromReturnUrl(string returnUrl, HttpContextBase httpContext) { if (string.IsNullOrWhiteSpace(returnUrl)) return (null, null); // 把相对路径转成绝对路径,确保路由能正确匹配 var baseUrl = httpContext.Request.Url.GetLeftPart(UriPartial.Authority); var absoluteUrl = new Uri(new Uri(baseUrl), returnUrl); // 创建路由上下文并让框架匹配路由 var routeContext = new RouteContext(httpContext); UrlRoutingModule.PostResolveRequestCache(new HttpContextWrapper(httpContext)); // 从RouteData里提取控制器和Action名称 var controller = routeContext.RouteData.Values["controller"]?.ToString(); var action = routeContext.RouteData.Values["action"]?.ToString(); return (controller, action); } }
2. 在登录的Post方法里用这个工具
假设你的登录提交方法是这样的,在用户登录成功后,就可以用上面的方法解析returnUrl,然后验证有效性和权限:
[HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<ActionResult> Login(LoginViewModel model, string returnUrl) { if (!ModelState.IsValid) { return View(model); } // 这里是你的用户登录验证逻辑 var signInResult = await SignInManager.PasswordSignInAsync( model.Email, model.Password, model.RememberMe, shouldLockout: false ); switch (signInResult) { case SignInStatus.Success: // 解析returnUrl对应的控制器和Action var (controllerName, actionName) = RouteHelper.GetControllerAndActionFromReturnUrl(returnUrl, HttpContext); // 验证URL是否有效,以及用户是否有权限访问 bool isValidUrl = !string.IsNullOrEmpty(controllerName) && !string.IsNullOrEmpty(actionName); bool hasAccessPermission = CheckUserPermission(controllerName, actionName); // 替换成你的权限检查逻辑 if (isValidUrl && hasAccessPermission) { return RedirectToLocal(returnUrl); } else { // 无效或无权限就跳转到仪表盘 return RedirectToAction("Index", "Dashboard"); } case SignInStatus.LockedOut: ModelState.AddModelError("", "你的账户已被锁定,请稍后重试。"); return View(model); case SignInStatus.RequiresVerification: return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe }); default: ModelState.AddModelError("", "登录失败,请检查用户名和密码是否正确。"); return View(model); } } // 示例权限检查方法,你可以根据自己的系统调整 private bool CheckUserPermission(string controller, string action) { // 比如检查用户角色是否有权限访问该控制器/Action return User.IsInRole($"CanAccess_{controller}_{action}"); }
3. 一些注意点
- 这个方法完全依赖MVC的路由系统,不管你是在
RouteConfig里定义的常规路由,还是用[Route]标记的属性路由,都能正确解析出控制器和Action。 - 记得处理
returnUrl为空或者格式错误的情况,避免空引用异常。 - 权限验证部分要根据你的实际权限体系来做,比如基于角色、基于声明或者自定义权限属性都可以。
内容的提问来源于stack exchange,提问作者Manprit Singh Sahota
相关产品推荐
相关产品推荐

