10

在ASP.NET中,FormsAuthenticationModule攔截任何HTTP 401,並將HTTP 302重定向返回到登錄頁面。這對AJAX來說是一種痛苦,因爲你要求使用json並使用html獲取登錄頁面,但狀態碼是HTTP 200.防止攔截ASP.NET Web API響應的FormsAuthenticationModule

在ASP.NET Web API中避免這種攔截的方式是什麼?

在ASP.NET MVC4它是很容易通過顯式結束連接,以防止這種攔截:

public class MyMvcAuthFilter:AuthorizeAttribute 
{ 
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) 
    { 
     if (filterContext.HttpContext.Request.IsAjaxRequest() && !filterContext.IsChildAction) 
     { 
      filterContext.Result = new HttpStatusCodeResult(401); 
      filterContext.HttpContext.Response.StatusCode = 401; 
      filterContext.HttpContext.Response.SuppressContent = true; 
      filterContext.HttpContext.Response.End(); 
     } 
     else 
      base.HandleUnauthorizedRequest(filterContext); 
    } 
} 

不過的ASP.NET Web API我也沒有明確終止連接,所以即使當我使用這個代碼FormsAuthenticationModule截取響應,併發送重定向到登錄頁面:

public class MyWebApiAuth: AuthorizeAttribute 
{ 
    protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext) 
    { 
     if(actionContext.Request.Headers.Any(h=>h.Key.Equals("X-Requested-With",StringComparison.OrdinalIgnoreCase))) 
     { 
      var xhr = actionContext.Request.Headers.Single(h => h.Key.Equals("X-Requested-With", StringComparison.OrdinalIgnoreCase)).Value.First(); 

      if (xhr.Equals("XMLHttpRequest", StringComparison.OrdinalIgnoreCase)) 
      { 
       // this does not work either 
       //throw new HttpResponseException(HttpStatusCode.Unauthorized); 

       actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized); 
       return; 
      } 
     } 

     base.HandleUnauthorizedRequest(actionContext); 
    } 
} 

什麼是避免的ASP.NET Web API這種行爲的方式是什麼?我一直在看,我找不到一個辦法。

問候。

PS:我不敢相信這是2012年,這個問題仍然存在。

+1

爲別人看,試試這個:http://blog.craigtp.co.uk/post/OWIN-Hosted-Web-API-in-an-MVC-Project – Sentinel

+0

@Sentinel發佈的鏈接修復了我的問題....謝謝! –

回答

4

MVC 4 RC的發行說明暗示自Beta以來已經解決了這個問題 - 您正在使用哪個?

通過的ASP.NET Web API返回處理401 Unauthroized

http://www.asp.net/whitepapers/mvc4-release-notes 未經授權的請求:通過的ASP.NET Web API來處理現在回到標準的401未授權的響應,而不是重定向用戶代理登錄表單的未經授權的請求,以便響應可以由Ajax客戶端處理。

尋找到用於MVC的源代碼似乎有經由SuppressFormsAuthRedirectModule.cs

http://aspnetwebstack.codeplex.com/SourceControl/network/forks/BradWilson/AspNetWebStack/changeset/changes/ae1164a2e339#src%2fSystem.Web.Http.WebHost%2fHttpControllerHandler.cs而添加的功能性。

internal static bool GetEnabled(NameValueCollection appSettings) 
    { 
      // anything but "false" will return true, which is the default behavior 

所以看起來這本是默認啓用和RC應該解決您的問題,沒有任何豪言壯語......作爲麪點看起來你可以使用的AppSettings http://d.hatena.ne.jp/shiba-yan/20120430/1335787815禁用此新模塊:

<appSettings> 
    <Add Key = "webapi:EnableSuppressRedirect" value = "false" /> 
</appSettings> 

編輯(例如和澄清)

現在我已經創造了在GitHub這種方法的例子。新的重定向抑制要求您使用兩個正確的「授權」屬性; MVC Web [System.Web.Mvc.Authorize]和Web API [System.Web.Http.Authorize]的全局過濾器中的AND/OR Link

然而,該示例確實提出了該方法的限制。看起來web.config中的「授權」節點總是優先於MVC路由,例如,這樣的配置將覆蓋你的規則,仍然重定向到登錄:

<system.web> 
    <authentication mode="Forms"> 
    </authentication> 
    <authorization> 
     <deny users="?"/> //will deny anonymous users to all routes including WebApi 
    </authorization> 
</system.web> 

可悲的是這個開放了使用地點元素不會出現某些URL路由的工作和來電的WebAPI將會繼續被攔截並重定向到登錄。

解決方案

對於MVC應用程序,我只是建議刪除從web.config中的配置,並與全局過濾器貼合,在代碼屬性。

如果您必須在MVC的Web.Config中使用授權節點,或者使用Hybrid ASP.NET和WebApi應用程序,那麼@PilotBob - 在下面的註釋中 - 已經發現子文件夾和多個Web.Config可用於有你的蛋糕,吃它。

+0

我正在使用測試版,因爲上週我試圖獲得最新版本,而DependencyResolver沒有像預期的那樣工作,所以Ninject MVC沒有工作,我嘗試了一些爲平均時間提出的解決方法,但沒有工作。你知道這件事嗎?太感謝了。 – vtortola

+1

@NullOrEmpty哦,好的。我在Ninject的RC上工作(從Autofac搬來,因爲我在RC初期就有問題)。這個鏈接描述了一種與我的相同的方法,應該很好地工作http://www.strathweb.com/2012/05/using-ninject-with-the-latest-asp-net-web-api-source/ –

+0

非常感謝!我稍後會試一試。 – vtortola

2

我能夠通過設置以下屬性,以繞過拒絕匿名設置在web.config中:

Request.RequestContext.HttpContext.SkipAuthorization = TRUE;

我在Global.asax.cs的Application_BeginRequest方法中對Request對象進行了一些檢查之後,比如RawURL屬性和其他標題信息,以確保請求正在訪問我想允許匿名訪問的區域。一旦API操作被調用,我仍然執行認證/授權。

5

萬一誰家有興趣使用的授權屬性在ASP.NET MVC應用程序具有相同的問題進行處理:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)] 
public class Authorize2Attribute : AuthorizeAttribute 
{ 
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) 
    { 
     if (filterContext.HttpContext.Request.IsAuthenticated) 
     { 
      filterContext.Result = new HttpStatusCodeResult((int) HttpStatusCode.Forbidden); 
     } 
     else 
     { 
      if (filterContext.HttpContext.Request.IsAjaxRequest()) 
      { 
       filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true; 
      } 
      base.HandleUnauthorizedRequest(filterContext); 
     } 
    } 
} 

這樣的瀏覽器,嚴禁轉載,未經授權的請求之間的區分正常..