16

在 ASP.NET MVC 项目中,当您使用 [Authorize] 装饰类或方法并且授权失败时,站点会自动重定向到登录页面(使用 web.config 中指定的 loginUrl)。此外,ASP.NET MVC 框架中的某些内容将原始请求的 URL 作为 ReturnUrl 参数传递。

是什么负责附加此 ReturnUrl?我在项目模板中找不到任何代码。我还查看了 ASP.NET 堆栈源代码中 AuthorizeAttribute 的代码,但在那里找不到任何东西。我还尝试在整个 ASP.NET 堆栈源代码中搜索“returnurl”,但找不到任何东西。

我问的原因是我在这个过程中发现了一个错误。您可以通过一个全新的 Internet ASP.NET MVC 项目看到这一点。在 web.config 中将 FormsAuth 超时设置为 1 分钟,然后登录。等待一分钟,然后尝试退出。这将重定向到带有 /account/logoff 的 ReturnUrl 的登录页面,登录后会导致 404。我现在已经使用自己的 AuthorizeAttribute 解决了这个问题:

public class MyAuthorizeAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        base.OnAuthorization(filterContext);

        if (filterContext.Result is HttpUnauthorizedResult)
        {
            string returnUrl = null;
            if (filterContext.HttpContext.Request.HttpMethod.Equals("GET", System.StringComparison.CurrentCultureIgnoreCase))
                returnUrl = filterContext.HttpContext.Request.RawUrl;

            filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary()
            {
                { "client", filterContext.RouteData.Values[ "client" ] },
                { "controller", "Account" },
                { "action", "Login" },
                { "ReturnUrl", returnUrl }
            });
        }
    }
}

但是,我想看看源代码,看看我是否可以弄清楚为什么这个错误存在,如果它确实是一个错误。

4

2 回答 2

11

returnUrl 查询字符串参数被添加到重定向到 System.Web.dll 程序集中 FormsAuthentication 类内的登录页面。FormsAuthenticion.RedirectToLoginPage 方法重载最终会调用内部方法 GetLoginPage。“ReturnUrl”变量的名称和 LoginUrl 都可以通过 web.config 设置覆盖。

当默认 AuthorizeAttribute 遇到未经授权的请求时,它只返回一个 HttpUnauthorizedResult,它只是 HttpStatusCodeResult 的包装器,状态码为 401。FormsAuthenticationModule 在幕后启动并完成其余工作。MVC 和这些基类之间没有直接的交互,当然除非您直接调用 FormsAuthentication 类的静态方法。

当您想要覆盖此行为时,您的解决方案是标准解决方案。

完成这项工作的 GetLoginPage 方法如下:

internal static string GetLoginPage(string extraQueryString, bool reuseReturnUrl)
{
    HttpContext current = HttpContext.Current;
    string loginUrl = FormsAuthentication.LoginUrl;
    if (loginUrl.IndexOf('?') >= 0)
    {
        loginUrl = FormsAuthentication.RemoveQueryStringVariableFromUrl(loginUrl, FormsAuthentication.ReturnUrlVar);
    }
    int num = loginUrl.IndexOf('?');
    if (num >= 0)
    {
        if (num < loginUrl.Length - 1)
        {
            loginUrl = string.Concat(loginUrl, "&");
        }
    }
    else
    {
        loginUrl = string.Concat(loginUrl, "?");
    }
    string str = null;
    if (reuseReturnUrl)
    {
        str = HttpUtility.UrlEncode(FormsAuthentication.GetReturnUrl(false), current.Request.QueryStringEncoding);
    }
    if (str == null)
    {
        str = HttpUtility.UrlEncode(current.Request.RawUrl, current.Request.ContentEncoding);
    }
    loginUrl = string.Concat(loginUrl, FormsAuthentication.ReturnUrlVar, "=", str);
    if (!string.IsNullOrEmpty(extraQueryString))
    {
        loginUrl = string.Concat(loginUrl, "&", extraQueryString);
    }
    return loginUrl;
}
于 2013-06-01T00:58:21.387 回答
1

尝试这个

 returnUrl = filterContext.HttpContext.Request.Url.GetComponents(UriComponents.PathAndQuery, UriFormat.SafeUnescaped) ;

我在这里找到了使用自定义 AuthorizeAttribute 生成返回 URL

这对我有用。

于 2015-08-14T12:40:09.647 回答