Что изначально задает параметр ReturnUrl при использовании AuthorizeAttribute

В проекте ASP.NET MVC, когда вы украшаете класс или метод с помощью [Авторизация] и авторизация завершается с ошибкой, сайт автоматически перенаправляется на страницу входа (используя loginUrl, указанный в web.config). Кроме того, что-то в структуре ASP.NET MVC проходит по исходному URL-адресу запроса в качестве параметра ReturnUrl.

Что несет ответственность за добавление этого ReturnUrl? Я не смог найти код для него в шаблоне проекта. Я также взглянул на код для AuthorizeAttribute в стеке исходного кода ASP.NET, но ничего не нашел. Я также попытался найти весь исходный код стека ASP.NET для "returnurl", но не смог найти что-либо.

Я прошу, что я обнаружил ошибку в этом процессе. Вы можете увидеть это с помощью нового интернет-проекта ASP.NET MVC. Установите тайм-аут FormsAuth на 1 минуту в файле web.config и войдите в систему. Подождите минуту и ​​попытайтесь выйти. Это перенаправит страницу входа с помощью ReturnUrl of/account/logff, что приведет к 404 после входа в систему. Я уже работал над этим с помощью своего авторизованного атрибута:

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 }
            });
        }
    }
}

Однако я хотел бы взглянуть на источник и посмотреть, могу ли я понять, почему эта ошибка существует, если она действительно является ошибкой.

Ответ 1

Параметр quurystring returnUrl добавляется к перенаправлению на страницу входа в класс FormsAuthentication в сборке System.Web.dll. Перегрузка метода 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;
}