2012-04-20 95 views
1

我正在爲我的網站編寫登錄功能。當用戶請求受我的[CustomAuthorize]屬性限制的視圖時,用戶將被正確重定向到/Login/Index視圖,並附加查詢字符串(?ReturnUrl=%2fRestricted%2fView)。MVC3 - 回傳後保留'returnUrl'?

但這裏有一個問題...

當用戶試圖登錄,並有一個驗證錯誤。發佈請求會導致回發(duh),並且附加的查詢字符串將從Url中消失。

  • 如何在回發後保留查詢字符串?

CustomAuthorize.cs:

public class CustomAuthorizeAttribute : AuthorizeAttribute 
{ 
     protected override bool AuthorizeCore(HttpContextBase httpContext) 
     { 
      if (httpContext.User.Identity.IsAuthenticated) 
      { 
       var customIdentity = (CustomIdentity)httpContext.User.Identity; 
       var customPrincipal = new CustomPrincipal(customIdentity); 

       if (customIdentity.IsAdmin) 
       { 
        httpContext.User = customPrincipal; 
        Thread.CurrentPrincipal = customPrincipal; 
       } 
      } 
      return base.AuthorizeCore(httpContext); 
     } 

     protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) 
     { 
      var urlRequested = filterContext.HttpContext.Request.Path; 
      //urlRequested contains "/Restricted/View" 
      //Do something with 'urlRequested' here, or? 
      base.HandleUnauthorizedRequest(filterContext); 
     } 
} 

登錄/索引視圖:

<body> 
     @using (Html.BeginForm("Index", "Login")) 
     { 
      <div> 
       @Html.LabelFor(model => model.UserName) 
      </div> 
      <div> 
       @Html.EditorFor(model => model.UserName) 
       @Html.ValidationMessageFor(model => model.UserName) 
      </div> 

      <div> 
       @Html.LabelFor(model => model.Password) 
      </div> 
      <div> 
       @Html.EditorFor(model => model.Password) 
       @Html.ValidationMessageFor(model => model.Password) 
      </div> 

      <div> 
       @Html.LabelFor(model => model.RememberMe) 
      </div> 
      <div> 
       @Html.EditorFor(model => model.RememberMe) 
       @Html.ValidationMessageFor(model => model.RememberMe) 
      </div> 

      <p> 
       <input type="submit" value="Login!" /> 
      </p> 
      @Html.ValidationSummary(true) 
     } 
</body> 

登錄/索引控制器動作:

[HttpPost] 
public ActionResult Index(LoginModelBinding login, string returnUrl) 
{ 
      if (ModelState.IsValid) 
      { 
       if (Service.CheckUser(login.UserName, login.Password)) 
       { 
        String loginError; 
        CustomAuthorization.Login(login.UserName, login.Password, out loginError); 

        if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/") && !returnUrl.StartsWith("/\\")) 
        { 
         return Redirect(returnUrl); 
        } 
        return RedirectToAction("Index", "MitTeam"); 

       } 
       ModelState.AddModelError("", "The entered user name or password is incorrect"); 
      } 
      return View(login); 
} 

SOLUTION: 按納文的回答我修改這樣的代碼:

public static void SaveReturnUrl(this Controller controller, string returnUrl, bool showAfterRedirect = true) 
{ 
      if (showAfterRedirect) 
      { 
       controller.TempData["returnUrl"] = returnUrl; 
      } 
      else 
      { 
       controller.ViewData["returnUrl"] = returnUrl; 
      } 
} 

public static string RetrieveReturnUrl(this Controller controller) 
{ 
      var message = controller.ViewData.ContainsKey("returnUrl") ? controller.ViewData["returnUrl"] : controller.TempData.ContainsKey("returnUrl") ? controller.TempData["returnUrl"] : null; 
      return message as string; 
} 

有了這兩個擴展方法,我可以保存和檢索我的登錄控制方法/行動RETURNURL。

var previousReturnUrl = this.RetrieveReturnUrl(); 
if(!ModelState.IsValid) 
{ 
    if(string.IsNullOrEmpty(previousReturnUrl)) 
    { 
     this.SaveReturnUrl(returnUrl); 
    } 
    return View(login); 
} 

而且,如果ModelState中是有效的,我只是叫this.RetrieveReturnUrl和解碼,所以我也可以把用戶在登錄成功的事件:

登錄POST方法。

回答

1

您可以使用由Martijn Boland - Keep your users informed開發的代碼模塊。它可以用來存儲任何對象並在重定向後將其取回。它專門用於在POST-REDIRECT操作後顯示操作的消息或狀態。這也適用於AJAX類型的請求。

在重定向後,您可能會使用同樣的方式將返回URL與消息一起存儲(認證失敗)。

+0

謝謝! 'ViewContext.TempData'幫助了我很多!將用我的解決方案編輯我的問題。 – KristianB 2012-04-23 08:15:06

0

您可以將視圖中的returnURL存儲在隱藏字段中。只要您將該隱藏字段以張貼回服務器的形式包含進來,您的POST-Action就可以根據Action的結果訪問和使用它(登錄成功 - >重定向到url,登錄失敗 - >返回用隱藏字段再次登錄視圖)。

+0

爲了在頁面上顯示驗證錯誤,我必須再次使用模型'LoginModelBinding'返回視圖。如果我只是重定向到returnurl,或者使用RouteValuesDictionary重定向到相同的View,則不顯示驗證錯誤。 – KristianB 2012-04-20 12:14:52