我的MVC 3 webapp有不同的部分,需要检查用户是用户还是管理员,他们都可以访问相同的页面,除了一些页面有控制器(按钮和文本框),只有管理员可以看到。我通过将用户的访问级别放入视图模型并执行检查来进行检查:
@if (Model.UserAccess != "Viewer")
{
[do something]
}
我在我的操作中检查登录用户的访问权限。如果会话超时,我将它们重定向到登录页面。
我的动作是从Project页面视图中调用的,并作为局部加载:
@{Html.RenderAction("CategoryList", "Home", new { categoryId = Model.CategoryId });}
和Controller:
public PartialViewResult CategoryList(int categoryid = 0)
{
var useraccess = GetUseraccess();
[blablabla stuff done here]
var model = new CategoryViewModel()
{
CategoryList = categorylist
UserAccess = useraccess
};
return PartialView(model);
}
public string GetUseraccess()
{
var useraccess = "viewer"; //default
var check = SessionCheck();
if (check == "expired")
{
ModelState.AddModelError("", "Session expired. Please login again.");
Response.Redirect("/Account/LogOn");
}
else if (check == "admin")
{
useraccess = "admin";
}
return useraccess;
}
public string SessionCheck()
{
if (Session["UserAccess"] == null)
{
return "expired";
}
else if ((string)Session["UserAccess"] == "admin")
{
return "admin";
}
else // viewer
{
return "viewer";
}
}
现在工作得很好。然而,我一直在尝试实现一个自定义属性,该属性将在控制器被触发之前检查会话的过期:
public class CheckUserAccessSessionAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var useraccess = filterContext.HttpContext.Session["UserAccess"];
if ((string)useraccess == null)
{
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { controller = "Account", action = "LogOn" }));
}
}
}
[CheckUserAccessSession]
public PartialViewResult CategoryList(int categoryid = 0)
{
[same stuff as above here]
}
我得到错误
Exception Details: System.InvalidOperationException: Child actions are not allowed to perform redirect actions.
我明白为什么会发生错误。但我还没找到绕过它的办法。同样,我想从另一个自定义属性发送到我的动作一些数据,但这也不工作,因为RedirectToRouteResult。
你在这里的问题是你在那个动作方法上返回一个PartialViewResult,根据定义,那个动作方法的输出将只是IIS提供的完整请求的一部分。您应该对服务于完整视图的操作方法进行权限检查,其中包含了部分视图。
当你调用响应时。重定向在你最初的实现中,你远离了ASP。. NET MVC设计规范;
使用这段代码。会成功的。
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
PartialViewResult result = new PartialViewResult();
result.ViewName = "noaccess";
filterContext.Result = result;
}