• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

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

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

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

问题场景

假设我们在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

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

【更新】

感谢彭伟在评论中指出上面的代码没有考虑cookie过期的的情况,下面的代码是针对MVC的一个解决方法:

public class BlogAuthorizeAttribute : AuthorizeAttribute
{
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        if (!httpContext.User.Identity.IsAuthenticated)
        {
            httpContext.Response.Redirect(FormsAuthentication.LoginUrl + "?ReturnUrl=" +
                HttpUtility.UrlEncode(httpContext.Request.Url.AbsoluteUri));
        }
        return base.AuthorizeCore(httpContext);
    }
}

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
开发asp.net自定义控件发布时间:2022-07-10
下一篇:
ASP.NET的六种验证控件,及正则表达式!!发布时间:2022-07-10
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap