2008-09-23 35 views
35

Làm thế nào để vô hiệu hóa việc xử lý tiêu chuẩn ASP.NET của mã phản hồi 401 (chuyển hướng đến trang đăng nhập) cho các yêu cầu AJAX/JSON?401 mã phản hồi cho các yêu cầu json với ASP.NET MVC

Đối với các trang web thì không sao, nhưng đối với AJAX, tôi cần nhận mã lỗi 401 đúng thay vì tìm kiếm 302/200 cho trang đăng nhập.

Cập nhật: Có một số giải pháp từ Phil Haack, PM của ASP.NET MVC - http://haacked.com/archive/2011/10/04/prevent-forms-authentication-login-page-redirect-when-you-donrsquot-want.aspx

Trả lời

18

các ASP.NET runtime được phát triển để nó luôn luôn sẽ chuyển hướng người dùng nếu HttpResponse.StatusCode được thiết lập để 401, nhưng chỉ khi phần <authentication /> của Web.config được tìm thấy

. Loại bỏ phần xác thực sẽ yêu cầu bạn để thực hiện chuyển hướng đến trang đăng nhập trong thuộc tính của bạn, nhưng điều này không nên là một việc lớn.

+0

Cách tốt nhất để thực hiện chuyển hướng của riêng bạn là phân lớp AuthorizeAttribute, và khi không được phép đặt kết quả thành một RedirectResult thay vì HttpUnauthorizedResult. –

+2

Có, nhưng trong trường hợp này OP muốn gửi mã HTTP 401, nhưng không chuyển hướng (để hoạt động đúng với JSON). –

+0

Làm việc cho tôi - mặc dù tôi đã định cấu hình cài đặt là thay vì xóa hoàn toàn thuộc tính. –

1

Bạn có thể chọn để tạo ra một tùy chỉnh FilterAttribute thực hiện giao diện IAuthorizationFilter.

Trong thuộc tính này, bạn thêm logic để xác định xem yêu cầu được giả định trả về JSON hay không. Nếu vậy, bạn có thể trả lại kết quả JSON trống (hoặc làm bất cứ điều gì bạn thích) do người dùng không đăng nhập. Đối với các câu trả lời khác, bạn sẽ chỉ chuyển hướng người dùng như mọi khi.

Thậm chí tốt hơn, bạn chỉ có thể ghi đè số OnAuthorization của lớp AuthorizeAttribute để bạn không phải phát minh lại bánh xe. Thêm logic tôi đã đề cập ở trên và đánh chặn nếu filterContext.Cancel là đúng (các filterContext.Result sẽ được thiết lập để một thể hiện của lớp HttpUnauthorizedResult.

Đọc thêm về "Filters in ASP.NET MVC CodePlex Preview 4" trên Phil Haacks blog. Nó cũng áp dụng cho chế độ xem trước mới nhất.

+0

Nhưng tôi vẫn không thể nhận được 401 mã trạng thái phản hồi cho yêu cầu AJAX. Ngay cả khi tôi thiết lập phản hồi trong bộ lọc Tự động hóa. Kể từ khi cơ sở hạ tầng ASP.NET bắt 401 phản ứng và chuyển hướng đến trang đăng nhập ngồi trên ASP.NET MVC. Để biết rằng người dùng không được ghi lại bằng kết quả JSON trống không phải là rất đúng ... – derigel

+0

Tôi không hiểu chính xác những gì bạn nghĩ đến cho đến bây giờ. Tôi đang thêm một câu trả lời mới sẽ giải quyết vấn đề của bạn. –

+1

làm cách nào bạn quản lý để đăng hai câu trả lời? :) – DevDave

2

Bạn cũng có thể sử dụng Global.asax để ngừng quá trình này với một cái gì đó như thế này:

protected void Application_PreSendRequestHeaders(object sender, EventArgs e) { 
     if (Response.StatusCode == 401) { 
      Response.Clear(); 
      Response.Redirect(Response.ApplyAppPathModifier("~/Login.aspx")); 
      return; 
     } 
    } 
+1

Tôi đã làm điều này, ngoại trừ tôi đã kiểm tra 302 và X-Requested-With trong câu trả lời từ @troethom ở trên. – Marc

24

Trong ASP.NET cổ điển bạn nhận được một mã phản hồi 401 http khi gọi một WebMethod với Ajax. Tôi hy vọng họ sẽ thay đổi nó trong các phiên bản tương lai của ASP.NET MVC. Hiện tại tôi đang sử dụng hack này:

protected void Application_EndRequest() 
{ 
    if (Context.Response.StatusCode == 302 && Context.Request.Headers["X-Requested-With"] == "XMLHttpRequest") 
    { 
     Context.Response.Clear(); 
     Context.Response.StatusCode = 401; 
    } 
} 
+0

Đây là một giải pháp ngăn chặn thực sự tốt nếu bạn cần một cái gì đó nhanh chóng hoạt động. Nếu không tôi sẽ cố gắng thực hiện câu trả lời @troethom. –

8

Tôi muốn cả Xác thực mẫu và trả về 401 cho các yêu cầu Ajax không được xác thực.

Cuối cùng, tôi đã tạo một AuthorizeAttribute tùy chỉnh và trang trí các phương thức điều khiển. (Đây là trên Net 4.5)

//web.config

<authentication mode="Forms"> 
</authentication> 

// điều khiển

[Authorize(Roles = "Administrator,User"), Response302to401] 
[AcceptVerbs("Get")] 
public async Task<JsonResult> GetDocuments() 
{ 
    string requestUri = User.Identity.Name.ToLower() + "/document"; 
    RequestKeyHttpClient<IEnumerable<DocumentModel>, string> client = 
     new RequestKeyHttpClient<IEnumerable<DocumentModel>, string>(requestUri); 

    var documents = await client.GetManyAsync<IEnumerable<DocumentModel>>(); 

    return Json(documents, JsonRequestBehavior.AllowGet); 
} 

// AuthorizeAttribute

public class Response302to401 : AuthorizeAttribute 
{ 
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) 
    { 
     if (!filterContext.HttpContext.User.Identity.IsAuthenticated) 
     { 
      if (filterContext.HttpContext.Request.IsAjaxRequest()) 
      { 
       filterContext.Result = new JsonResult 
       { 
        Data = new { Message = "Your session has died a terrible and gruesome death" }, 
        JsonRequestBehavior = JsonRequestBehavior.AllowGet 
       }; 
       filterContext.HttpContext.Response.StatusCode = 401; 
       filterContext.HttpContext.Response.StatusDescription = "Humans and robots must authenticate"; 
       filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true; 
      } 
     } 
     //base.HandleUnauthorizedRequest(filterContext); 
    } 
} 
+0

điều gì sẽ xảy ra nếu tôi muốn sử dụng biểu mẫu chuẩn cho phép chuyển hướng khi người dùng không đăng nhập, mà còn để gọi chuyển hướng 401 tùy chỉnh khi người dùng không có quyền liên quan, bất kỳ ý tưởng nào? – DevDave

+0

Bạn sẽ nhận được các hình thức chuyển hướng bình thường trên các phương thức không có AuthorizeAttribute này. Bạn cũng có thể mở rộng thuộc tính này bằng cách cung cấp mệnh đề "else" nếu if (! FilterContext.IsAuthenticated) trong đó bạn sẽ kiểm tra các quyền và sau đó tự thiết lập chuyển hướng. –

2

Tôi không thấy gì chúng tôi phải sửa đổi chế độ xác thực hoặc thẻ xác thực như câu trả lời hiện tại nói.

Theo ý tưởng của @TimothyLeeRussell (cảm ơn bằng cách này), tôi đã tạo một thuộc tính ủy quyền tùy chỉnh (vấn đề với một trong @TimothyLeeRussell là một ngoại lệ là ném vì anh ta cố gắng thay đổi filterContext.Result một tạo ra một HttpException, và loại bỏ phần đó, bên cạnh filterContext.HttpContext.Response.StatusCode = 401, mã phản hồi luôn là 200 OK). Vì vậy, cuối cùng tôi đã giải quyết vấn đề bằng cách kết thúc phản hồi sau khi thay đổi.

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] 
public class BetterAuthorize : AuthorizeAttribute 
{ 
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) 
    { 
     if (filterContext.HttpContext.Request.IsAjaxRequest()) 
     { 
      //Set the response status code to 500 
      filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized; 
      filterContext.HttpContext.Response.StatusDescription = "Humans and robots must authenticate"; 
      filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true; 

      filterContext.HttpContext.Response.End(); 
     } 
     else 
      base.HandleUnauthorizedRequest(filterContext); 
    } 
} 
+1

thuộc tính SuppressFormsAuthenticationRedirect chính xác là những gì tôi đang tìm kiếm. – zeocrash

1

Bạn có thể gọi phương pháp này bên trong hành động của bạn,

HttpContext.Response.End(); 

Ví dụ

public async Task<JsonResult> Return401() 
{ 
    HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized; 
    HttpContext.Response.End(); 
    return Json("Unauthorized", JsonRequestBehavior.AllowGet); 
} 

Từ MSDN: Phương pháp End làm cho máy chủ Web để ngừng xử lý kịch bản và trả lại hiện tại kết quả. Các nội dung còn lại của tập tin không được xử lý.

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