最近接連遇到幾次的需求:供內部使用的ASP.NET網站,全站使用Windows驗證,使用者以網域AD帳號登入,但網站包含少數API性質的ASHX、ASPX或MVC Action,提供其他系統呼叫整合。

此時問題來了,既為API性質,要求呼叫端程式用網域帳號登入徒增部署與管理的不便(需申請程式專用AD帳號、程式要綁特定式執行身分、每次改密碼時要記得修改)。對API而言,較理想的做法是開放Web API網頁匿名存取,改限制呼叫來源IP或採API Key等驗證機制進行安全管控。在不拆分Web Application前題下要達成這個目標有個基本要求:必須在啟用Windows驗證的IIS網站開放部分資料夾或路徑接受匿名存取。

方法不難,用下面的專案示範:(文章都寫完了,才發現MixAuth被我寫成FixAuth,XD)

有某個MVC專案,網站採Windows驗證,圖中黃色底線項目需開放匿名存取。我設計了幾個典型,開放匿名存取對象包含:MyApiController所有Action,HomeController的AllowAnonymous() Action,ForEveryone目錄下的Test.aspx(傳統WebForm)及Test.html。為驗證結果,可使用以下程式偵測是否為匿名,匿名時為False,Windows驗證時為True:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
 
namespace FixAuth.Controllers
{
    public class HomeController : Controller
    {
        // GET: Home
        public ActionResult Index()
        {
            return Content("IsAuthenticated=" + Request.IsAuthenticated);
        }
 
        public ActionResult AllowAnonymous()
        {
            return Content("IsAuthenticated=" + Request.IsAuthenticated);
        }
    }
}

 

<%@ Page Language="C#" AutoEventWireup="true" %>
<script runat="server">
    void Page_Load(object sender, EventArgs e)
    {
        Response.Write("IsAuthenticated=" + Request.IsAuthenticated);
        Response.End();
    }
</script>

首先,網站必須「同時」開放匿名驗證及Windows驗證,


IIS設定方式

 


IISExpress設定方式

接下來在web.config動點手腳,由於網站接受匿名存取,故先在<system.web>中加入<authorization><deny users="?" /></authorization>,預設整個網站拒絕匿名存取。針對要開放匿名存取的部分,則使用<location path="URL路徑">包住<authorization><allow users="?" /></authorization>,針對特定URL正向表列宣告接受匿名存取。

基本上,這樣就已滿足「部分網頁採Windows驗證,部分網頁開放匿名存取」的要求。但有一點需要注意,當網站同時啟用匿名及Windows兩種驗證,靜態檔案(如:html、js、css、jpg、png、zip、pdf…)將套用匿名存取規則,不需要登入就能下載。若此一行為不符合專案的資安要求,則要再動點手腳。設定<system.webServer><module runAllManagedModulesForRequests="true">是最簡單的解法,但所有靜態檔案都透過ASP.NET管線處理效能稍差,在效能要求較高的情境,可參照以下方法針對特定路徑加入Handler設定,可對該路徑的靜態檔案啟用Windows驗證。

以上就是在Windows驗證網站部分開放匿名存取的做法,提供大家參考。


Comments

# by 阿尼

hi黑大,我之前有用過反向的做法,網站同樣是要啟用匿名及windows認證,web.config則是設定authentication為Windows,這樣就全站可匿名了。然後需要windows認證的再用ActionFilter檢查User.Identity.IsAuthenticated,false的就吐個401回去

# by Jeffrey

to 阿尼,感謝經驗分享。

Post a comment