zoukankan      html  css  js  c++  java
  • FormsAuthentication登录ReturnUrl使用绝对路径

    ASP.NET]更简单的方法:FormsAuthentication登录ReturnUrl使用绝对路径

     

    被这个问题困扰多年,今天终于找到了更简单的解决方法,分享一下。

    问题场景

    假设我们在i.cnblogs.com站点的web.config中对FormsAuthentication进行了如下的设置:

    <authentication mode="Forms">
      <forms name=".cnblogs" loginUrl="https://passport.cnblogs.com/login.aspx" protection="All" path="/"/>
    </authentication>

    当我们访问一个需要登录后才能访问的URL时,比如:http://i.cnblogs.com/post/list,请求会被重定向至如下的地址:

    https://passport.cnblogs.com/login.aspx?ReturnUrl=%2fpost%2flist

    瞧!通过ReturnUrl查询参数传递给登录页面的是相对路径——这就是问题所在。由于访问的页面与登录页面不在同一个二级域名下,使用这个相对路径是Return不回来的。

    问题的根源

    用ILSPY看一下System.Web.Security.FormsAuthentication的代码,立马就能知道问题原因所在:

    复制代码
    internal static string GetLoginPage(string extraQueryString, bool reuseReturnUrl)
    {
        //...
        if (text2 == null)
        {
            text2 = HttpUtility.UrlEncode(current.Request.RawUrl, current.Request.ContentEncoding);
        }
        text = text + FormsAuthentication.ReturnUrlVar + "=" + text2;
        if (!string.IsNullOrEmpty(extraQueryString))
        {
            text = text + "&" + extraQueryString;
        }
        return text;
    }
    复制代码

    由码可见,微软根本就无视了登录页面不在同一个二级域名的基本应用场景,而且一直无视到现在。

    以前的解决方法

    在当前站点添加一个中转页面,由中转页面重定向至登录页面。

    于是,web.config的设置变成了如下的样子,先重定向至当前站点的登录中转页面。

    <authentication mode="Forms">
      <forms name=".cnblogs" loginUrl="~/account/login" protection="All" path="/"/>
    </authentication>

    然后,在中转页面使用绝对路径作为ReturnUrl的值,再重定向至真正的登录页面。

    中转页面的示例代码如下:

    复制代码
    public class AccountController : Controller
    { 
        public ActionResult Login(string ReturnUrl)
        {
            return Redirect("https://passport.cnblogs.com/login.aspx?ReturnUrl=" +
                HttpUtility.UrlEncode("http://" + Request.Url.Host) + ReturnUrl);
        }
    }
    复制代码

    虽然解决了问题,但是对于这样的解决方法,我觉得有些啰嗦,总觉得有更好的解决方法,可是一直没找到。

    今天再次面对这个问题时,狠了一下心,竟然有了意外的收获!

    更简单的解决方法

    Forms验证中,工作在第一线、最苦最累的是System.Web.Security.FormsAuthenticationModule。

    它在OnEnter(object source, EventArgs eventArgs)中调用了OnAuthenticate方法:

    复制代码
    // System.Web.Security.FormsAuthenticationModule
    private void OnEnter(object source, EventArgs eventArgs)
    {
        //...
        this.OnAuthenticate(new FormsAuthenticationEventArgs(context));
        //...
    }
    复制代码

    而在OnAuthenticate()方法中有如下的事件处理:

    复制代码
    private void OnAuthenticate(FormsAuthenticationEventArgs e)
    {
        HttpCookie httpCookie = null;
        if (this._eventHandler != null)
        {
            this._eventHandler(this, e);
        }    
        //...  
    复制代码

    再找到有关这个事件的代码:

    复制代码
    // System.Web.Security.FormsAuthenticationModule
    public event FormsAuthenticationEventHandler Authenticate
    {
        add
        {
            this._eventHandler = (FormsAuthenticationEventHandler)Delegate.Combine(this._eventHandler, value);
        }
        remove
        {
            this._eventHandler = (FormsAuthenticationEventHandler)Delegate.Remove(this._eventHandler, value);
        }
    }
    复制代码

    从这个地方下手,更简单的解决方法就浮出了水面——

    在Global.asax.cs中添加如下的代码:

    复制代码
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            //...
        }
    
        protected void FormsAuthentication_OnAuthenticate(Object sender, 
            FormsAuthenticationEventArgs e)
        {
            if (Request.Cookies[FormsAuthentication.FormsCookieName] == null)
            {
                Response.Redirect(FormsAuthentication.LoginUrl + "?ReturnUrl=" + 
                    HttpUtility.UrlEncode(e.Context.Request.Url.AbsoluteUri));
            }
        }
    }
    复制代码

    web.config中使用原先的设置:

    <authentication mode="Forms">
      <forms name=".cnblogs" loginUrl="https://passport.cnblogs.com/login.aspx" protection="All" path="/"/>
    </authentication>

    访问http://i.cnblogs.com/post/list时,会进行如下的重定向:

    https://passport.cnblogs.com/login.aspx?ReturnUrl=http%3a%2f%2fi.cnblogs.com/post/list

    如果微软继续无视这个问题,我想这就是最简单的解决方法。

     
     
     
    标签: ASP.NET
  • 相关阅读:
    Android异步操作总结
    datatable1.9 与datatable1.10以数据差异
    ftk学习记录(形成全屏幕套件)
    linux处置服务Iptables
    Linux课程---9、安装RPM包(RPM的全称是什么)
    Linux课程---8、Linux启动流程
    Linux课程---7、shell技巧(获取帮助命令)
    Linux课程---6、别名管理和网络配置(Linux命令如何记)
    Linux课程---5、常用文件命令和目录命令(创建文件命令)
    英语发音规则---L字母
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3553407.html
Copyright © 2011-2022 走看看