每個 ASP.NET 請求都會經歷完整生命週期,驗證與授權發生在特定管線事件。本文詳細說明請求從 IIS → ISAPI → ASP.NET 管線 → 頁面生命週期的流程,並聚焦 Application_AuthenticateRequest、Application_AuthorizeRequest 兩大關鍵事件與對應 HTTP 模組。
aspnet_isapi.dll)。w3wp.exe)。HttpRuntime → HttpApplication 建立/取自池。.aspx,進入頁面生命週期 (Init、Load、Render 等)。
Application_AuthenticateRequest (對應 AuthenticateRequest 事件)。FormsAuthenticationModule、WindowsAuthenticationModule、PassportAuthenticationModule、DefaultAuthenticationModule (匿名身分)。IIdentity → 包裝 IPrincipal → 指派 Context.User。IHttpModule,在 Init 掛接 context.AuthenticateRequest += ...。Application_AuthorizeRequest (對應 AuthorizeRequest 事件)。UrlAuthorizationModule (URL 授權)、FileAuthorizationModule (檔案授權)。web.config):<authorization>
<allow roles="Admin" />
<deny users="?" /> <!-- 匿名 -->
</authorization>Context.User.Identity 存取。
public class CustomAuthModule : IHttpModule
{
public void Init(HttpApplication app)
{
app.AuthenticateRequest += OnAuthenticate;
app.AuthorizeRequest += OnAuthorize;
}
private void OnAuthenticate(object sender, EventArgs e)
{
var app = (HttpApplication)sender;
// 從自訂 Header 讀取 Token
string token = app.Request.Headers["X-Auth-Token"];
if (!string.IsNullOrEmpty(token))
{
var principal = TokenService.Validate(token); // 回傳 IPrincipal
if (principal != null)
{
app.Context.User = principal;
Thread.CurrentPrincipal = principal;
}
}
}
private void OnAuthorize(object sender, EventArgs e)
{
var app = (HttpApplication)sender;
// 進一步細粒度授權邏輯
if (app.Context.Request.Path.StartsWith("/api/admin") &&
!app.Context.User.IsInRole("Admin"))
{
app.Context.Response.StatusCode = 403;
app.CompleteRequest(); // 短路管線
}
}
public void Dispose() { }
}
<system.webServer>
<modules>
<add name="CustomAuthModule" type="MyNamespace.CustomAuthModule, MyAssembly" preCondition="integratedMode" />
</modules>
</system.webServer>