Model view controller MVC 3页导航安全规则

Model view controller MVC 3页导航安全规则,model-view-controller,asp.net-mvc-3,Model View Controller,Asp.net Mvc 3,我有一个遵循PRG模式的MVC3应用程序,我正在寻找一种为我的应用程序定义导航规则的最佳方法。例如,我有一个页面A、B、C和D的应用程序。假设A是一个登录页面。用户成功登录后,用户将被重定向到B页。现在我不想让用户在地址栏中键入C页的url并访问C页(只有在发布B页或从D页返回按钮后才能访问C页),我还必须为所有其他页设置类似的规则(假设用户在D页时,不应允许他们进入B页) 目前,我有一个选项,可以检查@Request.UrlRefferer属性以获取每个请求的源,并决定重定向到哪个页面。我不确

我有一个遵循PRG模式的MVC3应用程序,我正在寻找一种为我的应用程序定义导航规则的最佳方法。例如,我有一个页面A、B、C和D的应用程序。假设A是一个登录页面。用户成功登录后,用户将被重定向到B页。现在我不想让用户在地址栏中键入C页的url并访问C页(只有在发布B页或从D页返回按钮后才能访问C页),我还必须为所有其他页设置类似的规则(假设用户在D页时,不应允许他们进入B页)

目前,我有一个选项,可以检查@Request.UrlRefferer属性以获取每个请求的源,并决定重定向到哪个页面。我不确定这是否是最佳解决方案


感谢您的反馈!!

不要将您的安全性建立在这个基础上。使用[Authorize]属性定义安全性。URLreferer也很容易伪造


你为什么要限制这一点?如果你有一个商业原因,用户最多会经历一个特定的流程,然后考虑cookie、session或数据库条目来记录他们当前的“完成”状态-伊江有一些持久的方法来确定这一点。ch页面。如果令牌存在并且与用户的当前会话匹配,则为其加载页面。当然,如果用户理解这一点,这可能是伪造的-但如果您只是试图确保正确的流,那么这也是一种方法。用户在点击上一步之前不会获得包含当前会话id的链接。

如果是您不希望通过URL访问特定页面,可用的一个选项是确保无法通过URL访问该页面。要访问该页面,请执行将返回视图而不是重定向的POST操作。这意味着您的POST操作返回的视图将显示在具有上一页URL的页面上。例如ple:

页面A的URL是
/login
,登录后,用户被重定向到页面B。URL现在是
/home
。页面B发送POST请求,页面内容变为页面C,但URL仍然保持为
/home
。查看页面C内容的唯一方法是访问页面B并发送POST请求

这打破了PRG模式,但这是一种选择

还有另一种选择,存储用户的当前权限,指示允许用户进入的页面,并在执行操作之前检查用户是否有权查看页面。您可以将代码放置在
ActionAttribute
中,您可以将其应用于您的操作方法或整个控制器。如果您想要更多关于这项技术的详细解释,请给我留言,我将写下另一个更详细描述这项技术的答案


下面是上述技术概念的快速证明:

public class PermissionsNeeded : ActionFilterAttribute
{
    string expectedPermission;

    public PermissionsNeeded(string permission)
    {
        expectedPermission = permission;
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var currentPermissions = filterContext.HttpContext.Session["CurrentPermissions"] as IEnumerable<string> ?? new List<string>();

        // If user does NOT have permission to access the action method
        if(!currentPermissions.Contains(expectedPermission)
        {
            throw new HttpException(403, "User is not authorized to view this page");
        }
    }
}

class YourController : Controller
{
    [HttpPost]
    public ActionResult PageB()
    {
        var currentPermissions = Session["CurrentPermissions"] ?? new List<string>();
        currentPermissions.Add("PostedFromPageB");
        Session["CurrentPermissions"] = currentPermissions;

        return RedirectToAction("PageC");
    }

    [PermissionsNeeded("PostedFromPageB")
    public ActionResult PageC()
    {
        return View();
    }
}
需要公共类权限:ActionFilterAttribute
{
字符串expectedPermission;
需要公共权限(字符串权限)
{
expectedPermission=许可;
}
公共覆盖无效OnActionExecuting(ActionExecutingContext filterContext)
{
var currentppermissions=filterContext.HttpContext.Session[“currentppermissions”]作为IEnumerable??new List();
//如果用户没有访问操作方法的权限
如果(!currentPermissions.Contains)(expectedPermission)
{
抛出新的HttpException(403,“用户无权查看此页面”);
}
}
}
类控制器:控制器
{
[HttpPost]
公共行动结果第b页()
{
var currentPermissions=会话[“currentPermissions”]??新列表();
currentPermissions.Add(“PostedFromPageB”);
会话[“CurrentPermissions”]=CurrentPermissions;
返回重定向到操作(“PageC”);
}
[需要许可证(“PostedFromPageB”)
公共行动结果页面C()
{
返回视图();
}
}

当前,自定义属性一次只接受一个权限,这只是一个需要纠正的限制。当您觉得用户不应该再拥有某些权限时,您将负责删除会话中存储的权限。我抛出了一个HttpException,返回403状态代码(未经授权的访问)但是,如果您想返回一个ActionResult,例如
重定向路由
视图
,则可以为
filterContext.Result
属性设置一个值。

我最终执行此任务,如下所示:

  • 成功完成每个页面后,将页面名称保存到数据库中
  • 当用户请求一个新页面时,只需从数据库中检查他们最后完成的页面并决定要做什么
  • 我之所以选择这种方法,是因为一旦应用程序投入生产,它肯定会在解决问题/排除故障时提供帮助,这对我来说是巨大的


    谢谢大家的回复!

    谢谢大家的回复。我不喜欢打破PRG模式。你能解释一下你的其他选择吗?@matmat:为我前面描述的替代方法添加了概念证明。可能需要一些更改以使其完全符合你的需要。如果你需要任何澄清,请告诉我。谢谢您的回答,尽管您的方法是一种选择,但我决定使用数据库,因为它有助于排除故障。请参考我下面的回答。感谢您的回答。是的,我正在尝试这样做,以确保正确的流程。我喜欢将完成状态存储在会话中,并在此基础上设置规则。但是,正如您所说如果URLRER和seesion id都可以伪造,那么想知道有没有最好的方法可以做到这一点?如果你不担心“手工篡改”,那么这两种方法都可以。