HttpPost to ReturnURL после перенаправления - PullRequest
6 голосов
/ 30 мая 2010

Я пишу приложение ASP.NET MVC 2.0, которое требует от пользователей входа в систему, прежде чем делать ставку на предмет. Я использую actionfilter, чтобы убедиться, что пользователь вошел в систему и, если нет, отправить его на страницу входа и установить URL-адрес возврата. Ниже приведен код, который я использую в своем фильтре действий.

if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
    filterContext.Result = new RedirectResult(String.Concat("~/Account/LogOn","?ReturnUrl=",filterContext.HttpContext.Request.RawUrl));
    return;
}

В контроллере входа в систему я проверяю учетные данные пользователей, затем регистрирую их и перенаправляю на возвращаемый URL

FormsAuth.SignIn(userName, rememberMe);
if (!String.IsNullOrEmpty(returnUrl))
{
    return Redirect(returnUrl);
}

Моя проблема в том, что при этом всегда будет использоваться запрос Get (HttpGet), в то время как моя первоначальная отправка была постом (HttpPost) и всегда должна быть постом. Кто-нибудь может предложить способ передачи этого URL, включая HttpMethod или любой обходной путь, чтобы убедиться, что используется правильный HttpMethod?

Ответы [ 3 ]

8 голосов
/ 30 мая 2010

Нет простого способа сделать это. Я бы порекомендовал вам перенаправить неаутентифицированных пользователей на страницу входа не при публикации на какой-либо URL, а при запросе формы, которая отправит POST на аутентифицированный URL.

Если вы знаете, что форма, которую вы предоставляете неаутентифицированному пользователю, отправит POST на аутентифицированную часть сайта, не предоставляйте ему форму. Когда запрашивается эта форма, просто перенаправьте на страницу входа для аутентификации и один раз аутентифицируйте, перенаправьте на исходную форму. Таким образом вы гарантируете, что только аутентифицированные пользователи будут отправлять POST к защищенному ресурсу.

Что касается автоматических запросов POST (боты, веб-службы, ...), то возврата простого кода состояния 401 запросам, которые не предоставляют учетные данные, должно быть более чем достаточно.

7 голосов
/ 01 июня 2010

Я думаю, я понимаю, почему вы хотите, чтобы аутентификация была включена только в действие ставки POST. Ставка требует входа в систему, но любой не авторизованный пользователь может видеть страницу аукциона. Точно так же как ebay / amazon и т. Д. Все видно, пока вы не потребуете оплаты или действия на основе пользователя.

Вы можете изменить свой атрибут, чтобы вместо этого возвращать Request.UrlReferrer на страницу входа, если Request.RequestType - это POST. Затем они будут перенаправлены на страницу аукциона и могут снова щелкнуть ставку, как только они войдут в систему. Вы можете даже передать определенное поле, скажем, сумму, с помощью UrlReferrer, чтобы вы могли повторно заполнить поле суммы после их приземления на странице аукциона. Вы можете получить это поле из коллекции Request.Form.

// in usage...    
[RequireLogin(AdditionalFields="amount,someotherfield")]
[HttpPost]
public ActionResult Bid(.....)

// the attribute 
class RequireLoginAttribute : ActionFilterAttribute
{
    public string AdditionalFields { get; set; }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
        {
            var returnUrl = filterContext.HttpContext.Request.RawUrl;
            if (filterContext.HttpContext.Request.RequestType == "POST")
            {
                returnUrl = filterContext.HttpContext.Request.UrlReferrer.PathAndQuery;
                // look for FORM values in request to append to the returnUrl
                // this can be helpful for a good user experience (remembering checkboxes/text fields etc)
            }

            filterContext.Result = new RedirectResult(String.Concat("~/Account/LogOn", "?ReturnUrl=", returnUrl));
            return;
        }
        base.OnActionExecuting(filterContext);
    }
}
2 голосов
/ 20 ноября 2010

Вы можете написать два метода Controller с одинаковым именем, но один для get и другой для post, и вспомнить ReturnUrl в методе get в TempData (или сеансе), а затем получить ReturnUrl из TempData, когда поступит запрос post:

Код может выглядеть так:

    public ActionResult LogOn(string returnUrl)
    {
        if (!string.IsNullOrEmpty(returnUrl))
        {
            TempData["ReturnUrl"] = returnUrl;
        }
        return View();
    }

    [HttpPost]
    public ActionResult LogOn(LogOnModel model, FormCollection collecton)
    {
        if (ModelState.IsValid)
        {
            AuthenticationResult logonStatus = TransactionScriptFactory.GetTransactionScript<UserTransactionScripts>()
                                                                       .LogOn(model.Email, model.Password);

            if (logonStatus.AuthResult == AuthResultEnum.Success)
            {
                FormsService.SignIn(logonStatus.User.UserId, logonStatus.User.NickName, false);

                object returnUrl = string.Empty;
                TempData.TryGetValue("ReturnUrl", out returnUrl);
                string returnUrlStr = returnUrl as string;
                if (!string.IsNullOrEmpty(returnUrlStr))
                {
                    return Redirect(returnUrlStr);
                }
                else
                {
                    return RedirectToAction("Index", "Home");
                }
            }

......

Это определенно, когда вы впервые попадаете на страницу с помощью действия get, а затем отправляете данные на сервер.

Я думаю, вы также можете получить весь URL-адрес из Request.UrlReferrer.

...