模型视图控制器 - MVC 3 页面导航安全规则



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

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

感谢您的反馈!!

不要以此为基础进行安全。使用 [授权] 属性定义安全性。UrlReferrer也可以很容易地伪造。

你为什么要限制这一点?如果您有用户最常经历特定流程的业务原因,请考虑使用 cookie、会话或数据库条目来记录其当前的"完成"状态 - IE 某种持久性方法来确定这一点。您还可以根据 say (会话 ID( 形成一个令牌,该令牌将传递到每个页面中。如果令牌存在并且与用户的当前会话匹配,则为其加载页面。当然,如果用户理解这一点,这可以伪造 - 但如果您只是想确保正确的流程,那么这也是一种方法。用户在点击上一步之前不会获得包含当前会话 ID 的链接。

如果您不希望通过 URL 访问

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

页面 A URL /login,登录后,用户被重定向到页面 B。网址现在已/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();
    }
}

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

我最终执行此任务如下:

  1. 成功完成每个页面后,将页面名称保存在数据库中
  2. 当用户请求新页面时,只需从数据库中检查他们上次完成的页面并决定要做什么。

我选择这种方法只是因为一旦应用程序进入生产环境,它肯定会在解决问题/故障排除期间有所帮助,这对我来说是巨大的。

感谢大家的回复!

最新更新