无Cookie会话和跨站点表单提交

5

现状如下:

网站1)ASP.NET MVC应用程序,供客户登录,查看和支付账单等。该网站使用无cookie ASP会话,允许在选项卡式浏览器中运行多个会话。

网站2)标准静态内容的公司网站。每个页面顶部都有一个带有用户名/密码表单的小表单,将提交到MVC应用程序。

当提交到MVC应用程序时,会生成一个新会话,并返回带有会话ID的302重定向URL(预期行为)。控制器有两个Login方法,一个用于处理GET请求,另一个用于处理POST请求。由于重定向,它会命中GET方法并且失去了表单值。

通过将公司网站上的方法更改为使用表单GET而不是POST,用户名和密码在重定向后会被保留在查询字符串中,可以通过这种方式处理请求,但我宁愿使用POST而不是在URL中传递数据。

我的直觉告诉我,实施某种自定义HttpHandler将允许我执行此操作,但我不确定在哪里能够连接到会话创建。在global.asax中的Session_Start处设置断点显示会话ID已经被创建并且重定向已经发生。

3个回答

2
我相信我已经找到了重定向发生的地方,以及可能的解决方案。ISessionIDManager接口有一个SaveSessionID方法,其中包含一个"out bool redirected"参数。当创建新会话时,默认会话管理器在此方法内部重写URL并进行重定向。我尝试实现自己的ISessionIDManager,并成功抑制了重定向,但是我没有找到在不进行重定向的情况下将会话ID插入到无cookie会话的URL中的方法。在请求生命周期的那个点上,Server.Transfer是不允许的。我尝试过这样做,但收到了"Error Executing Child Request"的消息。
后来,我在启用cookieless ASP.NET应用程序中的POST文章中找到了解决方案。基本上,通过连接到Application_EndRequest事件,您可以检测重定向,清除响应并伪造一个包含会话ID的新URL的表单提交。
void MvcApplication_EndRequest(object sender, EventArgs e)
{

    HttpApplication application = (HttpApplication)sender;

    if (application.Request.Form["CorpLogin"] == "1"
        && application.Response.RedirectLocation != null
        && application.Response.IsRequestBeingRedirected)
    {

        StringBuilder build = new StringBuilder();
        build.Append("<html>\n<body>\n<form name='Redirect' method='post' action='");
        build.Append(application.Response.RedirectLocation);

        build.Append("' id='Redirect' >");
        foreach (string key in application.Request.Form)
        {
            if (key != "CorpLogin")
                build.Append(string.Format("\n<input type='hidden' name='{0}' value = '{1}'>", (string)key, application.Request.Form[(string)key]));
        }

        build.Append("\n<noscript><h2>Object moved <input type='submit' value='here'></h2></noscript>");
        build.Append(@"</form>
      <script language='javascript'>
      <!--
        document.Redirect.submit();
      // -->
      </script>
      ");
        build.Append("</body></html>");

        application.Response.Clear();
        application.Response.ClearHeaders();
        application.Response.Output.Flush();

        application.Response.Write(build.ToString());

    }
}

在我看来,这并不是一个理想的解决方案,但它可能足以满足要求。


你能展示一下在EndRequest中如何检测重定向并清除响应吗?我想只需要这一部分... - Fedor Alexander Steeman

0

当MVC网站发出重定向时,您是通过控制器自己处理还是由会员提供者自动路由?

如果您可以在重定向之前拦截请求,则可以将用户名和密码放入TempData变量中,并在重定向后进行处理。


它正在自动重定向。 - Pete Nelson
当用户尝试登录时,远程站点会向哪个控制器/操作发送POST请求? - Nathan Taylor
现在我只是使用VS Web服务器,所以表单提交到"http://localhost:2600/Home/Login",方法看起来像...'[HttpPost] public ActionResult Login(HomeLoginData loginData) { // snip }'但由于新会话ID的重定向,它永远不会到达那里。例如,企业网站表单POST到http://localhost:2600/Home/Login,然后我得到一个302重定向到http://localhost:2600/%28S%28lkcfoer1mb1gbf55hi1bqsbn%29%29/Home/Login - Pete Nelson

0

你正在寻找一个在MVC中等价于Server.Transfer的方法(请参见Simon的回答)。

它类似于Request.Redirect,但只是将.NET处理简单地转移到另一个页面。它还允许在传输之间保持表单变量,即在这种情况下的RouteValueDictionary。

编辑:(回应您的评论#1)

这里有一个MVC中的Forms身份验证示例。如果不知道您的授权机制的内部工作原理,我不太确定。在“DoLogin”过程的任何时候,您都可以执行传输而不是重定向。


我该在哪里拦截第一个无会话表单提交以防止创建会话后的默认302重定向? - Pete Nelson
看看我的编辑 - 或许它会指引你朝着正确的方向。 - Peter J

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接