2012-10-19 53 views
32

Đây là kịch bản:Cách xử lý đúng HttpAntiForgeryException trong ứng dụng MVC 4

Tôi có trang đăng nhập, khi người dùng ký tên, nó được chuyển hướng đến trang ứng dụng tại nhà. Sau đó, người dùng đang sử dụng nút quay lại trình duyệt và giờ đây anh ấy đang ở trên trang đăng nhập. Anh ấy cố gắng đăng nhập lại nhưng giờ đây có một ngoại lệ được ném:

HttpAntiForgeryException (0x80004005): Mã thông báo chống giả mạo được cung cấp cho người dùng "", nhưng người dùng hiện tại là "userName".

Tôi biết điều này có liên quan đến bộ nhớ đệm. Tôi vô hiệu hóa bộ nhớ đệm trình duyệt cho action login sử dụng bộ lọc tùy chỉnh nocache mà đặt tất cả các tiêu đề cần thiết - no-cache, không có cửa hàng,-phải xác nhận lại, vv Nhưng

  • này không hoạt động trên tất cả các trình duyệt
  • đặc biệt là Safari (điện thoại di động trong hầu hết các trường hợp) totaly bỏ qua các cài đặt như vậy

Tôi sẽ cố gắng tạo hacks và buộc safari di động làm mới, nhưng đây không phải là những gì tôi mong đợi.

Tôi muốn biết nếu tôi có thể:

  • xử lý ngoại lệ mà không hiển thị sử dụng bất kỳ vấn đề tồn tại (hoàn toàn minh bạch cho người dùng)
  • ngăn chặn vấn đề này bằng cách thay thế chống giả mạo tên người dùng thẻ mà sẽ cho phép người dùng đăng nhập lại mà không có ngoại lệ này, nếu hacks của tôi liên quan đến bộ nhớ đệm của trình duyệt sẽ ngừng hoạt động trong các phiên bản trình duyệt tiếp theo.
  • Tôi thực sự không muốn dựa vào hành vi của trình duyệt vì mỗi hành vi đều khác nhau.

UPDATE 1

Để thực hiện một số giải thích, tôi biết làm thế nào để xử lý những sai sót trong MVC. Vấn đề là các lỗi xử lý này không giải quyết được vấn đề của tôi chút nào. Ý tưởng cơ bản về xử lý lỗi là chuyển hướng đến trang lỗi tùy chỉnh với thông điệp đẹp. Nhưng tôi muốn ngăn chặn lỗi này xảy ra, không phải để xử lý nó theo cách hiển thị của người dùng. Bằng cách xử lý tôi có nghĩa là bắt làm cho tên người dùng thay thế hoặc hành động thích hợp khác sau đó tiếp tục đăng nhập.

UPDATE 2

Tôi đã thêm dưới đây giải pháp mà đang làm việc cho tôi.

Trả lời

16

Sau một thời gian điều tra, tôi nghĩ rằng tôi đã tìm ra cách để loại bỏ lỗi này cho người dùng. Nó không phải là hoàn hảo nhưng ít nhất là không hiển thị trang báo lỗi:

tôi tạo ra bộ lọc dựa trên HandleErrorAttribute:

[SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes", 
     Justification = "This attribute is AllowMultiple = true and users might want to override behavior.")] 
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)] 
    public class LoginAntiforgeryHandleErrorAttribute : FilterAttribute, IExceptionFilter 
    { 
     #region Implemented Interfaces 

     #region IExceptionFilter 

     /// <summary> 
     /// </summary> 
     /// <param name="filterContext"> 
     /// The filter context. 
     /// </param> 
     /// <exception cref="ArgumentNullException"> 
     /// </exception> 
     public virtual void OnException(ExceptionContext filterContext) 
     { 
      if (filterContext == null) 
      { 
       throw new ArgumentNullException("filterContext"); 
      } 

      if (filterContext.IsChildAction) 
      { 
       return; 
      } 

      // If custom errors are disabled, we need to let the normal ASP.NET exception handler 
      // execute so that the user can see useful debugging information. 
      if (filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled) 
      { 
       return; 
      } 

      Exception exception = filterContext.Exception; 

      // If this is not an HTTP 500 (for example, if somebody throws an HTTP 404 from an action method), 
      // ignore it. 
      if (new HttpException(null, exception).GetHttpCode() != 500) 
      { 
       return; 
      } 

      // check if antiforgery 
      if (!(exception is HttpAntiForgeryException)) 
      { 
       return; 
      } 

      filterContext.Result = new RedirectToRouteResult(
       new RouteValueDictionary 
       { 
        { "action", "Index" }, 
        { "controller", "Home" } 
       }); 

      filterContext.ExceptionHandled = true; 
     } 

     #endregion 

     #endregion 
    } 

Sau đó, tôi áp dụng bộ lọc này để đăng nhập POST hành động:

[HttpPost] 
[AllowAnonymous] 
[ValidateAntiForgeryToken] 
[LoginAntiforgeryHandleError] 
public ActionResult Login(Login model, string returnUrl) 
{ 

Ý tưởng chính của giải pháp này là để chuyển hướng ngoại lệ chống giả mạo cho hành động chỉ mục chính. Nếu người dùng sẽ vẫn không được xác thực, nó sẽ hiển thị sau đó đăng nhập trang nếu người dùng sẽ được xác thực, trang sẽ hiển thị chỉ mục trang.

CẬP NHẬT 1 Có một vấn đề có thể xảy ra với giải pháp này. Nếu ai đó đang đăng nhập với các thông tin đăng nhập khác nhau thì lỗi sẽ được thêm vào thời gian đăng nhập bổ sung - đăng xuất người dùng trước đó và đăng nhập vào tài khoản mới. Kịch bản này không được xử lý.

+0

điều này làm việc tuyệt vời cho tôi. Tôi không cần nó để làm bất kỳ ưa thích. Chỉ cần không ném màn hình màu vàng. – hal9000

5

Bạn sẽ có thể xử lý ngoại lệ bằng cách thêm bộ lọc hành động để xử lý lỗi của mình.

[HandleError(View="AntiForgeryExceptionView", ExceptionType = typeof(HttpAntiForgeryException))] 

Do đó hãy đảm bảo rằng lỗi tùy chỉnh được bật trong web.config của bạn.

<customErrors mode="On"/> 

Bạn cũng có thể xem điều này blog để biết thêm thông tin về lỗi xử lý.

Chỉnh sửa Vì bạn đang sử dụng MVC4 và blog là về MVC3, bạn cũng có thể xem MSDN library - HandleErrorAttribute, nhưng phiên bản không thực sự tạo sự khác biệt.

+0

có, nhưng tất cả điều này nói về việc chuyển hướng (để xử lý lỗi này phá vỡ hành động hiện tại (thực thi). hành động, vì vậy trong trường hợp này xử lý, thay thế tên người dùng và tiếp tục đăng nhập với dữ liệu thích hợp – Marcin

+0

Tôi nghĩ rằng khi bạn ca n bắt lỗi bạn có thể chuyển hướng nó đến một khung nhìn (bộ điều khiển), nơi bạn thay thế tên người dùng và tiếp tục đăng nhập, với dữ liệu đã nhập trước đó. Ngoài ra, hãy xem: http://stackoverflow.com/questions/1794936/how-do-i-pass-viewdata-to-a-handleerror-view –

15

Nếu bạn chỉ có một hoặc một vài chức năng bị ảnh hưởng, việc tạo bộ lọc có thể hơi quá mức kỹ thuật. Một giải pháp đơn giản hơn nhưng không chung chung là chỉ cần loại bỏ các [ValidateAntiForgeryToken] cho phương pháp cụ thể và thêm một xác nhận sổ tay sau khi kiểm tra nếu người dùng đang đăng nhập

if (User.Identity.IsAuthenticated) 
{ 
    return RedirectToAction("Index", "Home"); 
} 
System.Web.Helpers.AntiForgery.Validate(); 
/* proceed with authentication here */ 
+0

Cảm ơn, điều này dường như hoạt động tốt và vẫn cung cấp cùng một bảo mật. –

+0

điều này không làm việc với tôi, nó cung cấp cho chính xác cùng một lỗi nhưng trên dòng này: System.Web.Helpers.AntiForgery.Validate(); –

1

Một câu hỏi cũ -. Nhưng tôi chạy vào vấn đề này ngày hôm nay, và cách tôi giải quyết nó bằng cách chuyển hướng đến hành động đăng xuất như vậy:

public ActionResult Login(string returnUrl) 
{ 
    if (WebSecurity.IsAuthenticated) 
     return RedirectToAction("LogOff"); 

    ... 
} 
Các vấn đề liên quan