Asp.net

關閉一個子目錄的 ASP.Net WebForms 身份驗證

  • August 23, 2019

我有一個包含 WebForms 和 MVC 頁面的大型企業應用程序。它具有我不想更改的現有身份驗證和授權設置。

WebForms 身份驗證在 web.config 中配置:

<authentication mode="Forms">
 <forms blah... blah... blah />
</authentication>

<authorization>
 <deny users="?" />
</authorization>

到目前為止相當標準。我有一個 REST 服務,它是這個大型應用程序的一部分,我想對這個服務使用 HTTP 身份驗證。

因此,當使用者嘗試從 REST 服務獲取 JSON 數據時,它會返回 HTTP 401 狀態和WWW-Authenticate標頭。如果他們以正確格式的 HTTPAuthorization響應進行響應,它將允許他們進入。

問題是 WebForms 在低級別覆蓋了它 - 如果您返回 401(未經授權),它會用 302(重定向到登錄頁面)覆蓋它。這在瀏覽器中很好,但對 REST 服務無用。

我想關閉 web.config 中的身份驗證設置,覆蓋“rest”文件夾:

<location path="rest">
 <system.web>
  <authentication mode="None" />
  <authorization><allow users="?" /></authorization>
 </system.web>
</location>

授權位工作正常,但身份驗證行 ( <authentication mode="None" />) 會導致異常:

在應用程序級別之外使用註冊為 allowDefinition=‘MachineToApplication’ 的部分是錯誤的。

我在應用程序級別配置它 - 它在根 web.config 中 - 並且該錯誤是針對子目錄中的 web.configs 的。

如何覆蓋身份驗證,以便站點的所有其餘部分都使用 WebForms 身份驗證,而這個目錄不使用任何身份驗證?

這類似於另一個問題:401 response code for json requests with ASP.NET MVC,但我不是在尋找相同的解決方案 - 我不想只是刪除 WebForms 身份驗證並在全域範圍內添加新的自定義程式碼,還有很遠涉及很多風險和工作。我只想更改配置中的一個目錄。

更新

我想設置一個 Web 應用程序,並且我希望所有 WebForms 頁面和 MVC 視圖都使用 WebForms 身份驗證。我希望一個目錄使用基本的 HTTP 身份驗證。

請注意,我說的是身份驗證,而不是授權。我希望 REST 呼叫帶有 HTTP 標頭中的使用者名和密碼,並且我希望 WebForm 和 MVC 頁面帶有來自 .Net 的身份驗證 cookie - 在任何一種情況下,授權都是針對我們的數據庫進行的。

我不想重寫 WebForms 身份驗證並滾動我自己的 cookie - 這是將 HTTP 授權的 REST 服務添加到應用程序的唯一方法似乎很荒謬。

我不能添加額外的應用程序或虛擬目錄 - 它必須作為一個應用程序。

我已經以混亂的方式解決了這個問題 - 通過在 global.asax 中為所有現有頁面欺騙 Forms 身份驗證。

我仍然沒有完全工作,但它是這樣的:

protected void Application_BeginRequest(object sender, EventArgs e)
{
   // lots of existing web.config controls for which webforms folders can be accessed
   // read the config and skip checks for pages that authorise anon users by having
   // <allow users="?" /> as the top rule.

   // check local config
   var localAuthSection = ConfigurationManager.GetSection("system.web/authorization") as AuthorizationSection;

   // this assumes that the first rule will be <allow users="?" />
   var localRule = localAuthSection.Rules[0];
   if (localRule.Action == AuthorizationRuleAction.Allow &&
       localRule.Users.Contains("?"))
   {
       // then skip the rest
       return;
   }

   // get the web.config and check locations
   var conf = WebConfigurationManager.OpenWebConfiguration("~");
   foreach (ConfigurationLocation loc in conf.Locations)
   {
       // find whether we're in a location with overridden config
       if (this.Request.Path.StartsWith(loc.Path, StringComparison.OrdinalIgnoreCase) ||
           this.Request.Path.TrimStart('/').StartsWith(loc.Path, StringComparison.OrdinalIgnoreCase))
       {
           // get the location's config
           var locConf = loc.OpenConfiguration();
           var authSection = locConf.GetSection("system.web/authorization") as AuthorizationSection;
           if (authSection != null)
           {
               // this assumes that the first rule will be <allow users="?" />
               var rule = authSection.Rules[0];
               if (rule.Action == AuthorizationRuleAction.Allow &&
                   rule.Users.Contains("?"))
               {
                   // then skip the rest
                   return;
               }
           }
       }
   }

   var cookie = this.Request.Cookies[FormsAuthentication.FormsCookieName];
   if (cookie == null ||
       string.IsNullOrEmpty(cookie.Value))
   {
       // no or blank cookie
       FormsAuthentication.RedirectToLoginPage();
   }

   // decrypt the 
   var ticket = FormsAuthentication.Decrypt(cookie.Value);
   if (ticket == null ||
       ticket.Expired)
   {
       // invalid cookie
       FormsAuthentication.RedirectToLoginPage();
   }

   // renew ticket if needed
   var newTicket = ticket;
   if (FormsAuthentication.SlidingExpiration)
   {
       newTicket = FormsAuthentication.RenewTicketIfOld(ticket);
   }

   // set the user so that .IsAuthenticated becomes true
   // then the existing checks for user should work
   HttpContext.Current.User = new GenericPrincipal(new FormsIdentity(newTicket), newTicket.UserData.Split(','));

}

我對此不太滿意——這似乎是一個可怕的黑客和輪子的重新發明,但看起來這是我的表單認證頁面和 HTTP 認證 REST 服務工作的唯一方法相同的應用程序。

如果“rest”只是根目錄中的一個文件夾,那麼您幾乎就在那裡:刪除身份驗證行,即

<location path="rest">
 <system.web>
     <authorization>
       <allow users="*" />
     </authorization>
 </system.web>
</location>

或者,您可以將 web.config 添加到您的 rest 文件夾中,然後就可以了:

<system.web>
    <authorization>
         <allow users="*" />
    </authorization>
</system.web>

檢查這個

引用自:https://stackoverflow.com/questions/4616524