如何使用 C# 管理登錄和身份驗證

在 C# 中,透過登入驗證將 HTML 轉換為 PDF

This article was translated from English: Does it need improvement?
Translated
View the article in English

若要在 C# 中透過登入驗證,或在轉換前轉換為 PDF,請使用 IronPDF 的 ChromeHttpLoginCredentials 進行網頁驗證,或在轉換前使用 HttpClient 下載 HTML。 這種方法可以有效地處理網頁認證和 HTML 表單登入。

快速入門:使用IronPDF在登入後將 HTML 轉換為 PDF

使用 IronPDF 的 API 將登入表單後面的 HTML 頁面轉換為 PDF。 本指南示範了 ChromeHttpLoginCredentials 的驗證和受保護內容檢索。 透過簡潔的程式碼範例,處理網頁驗證和 HTML 表單登入。

  1. 使用NuGet套件管理器安裝https://www.nuget.org/packages/IronPdf

    PM > Install-Package IronPdf
  2. 複製並運行這段程式碼。

    new ChromePdfRenderer { LoginCredentials = new ChromeHttpLoginCredentials("username","password") }
        .RenderUrlAsPdf("https://example.com/protected")
        .SaveAs("secure.pdf");
  3. 部署到您的生產環境進行測試

    今天就在您的專案中開始使用免費試用IronPDF

    arrow pointer


處理登入身分驗證的最佳實踐是什麼?

IronPDF支援透過ChromeHttpLoginCredentials API進行 TLS 網路驗證(使用者名稱和密碼)。 有關各種登入場景的全面指導,請參閱TLS 網站和系統登入教學

建議的方法是使用 System.Net.WebClientHttpClient 下載 HTML 和資源。 此方法支援標頭、登入和其他要求。 下載到記憶體或磁碟後, IronPDF會將 HTML 轉換為 PDF。 使用 HtmlAgilityPack 提取樣式表和圖像等資源,然後使用 System.Net.WebClient 下載。

// Download HTML content from a URL with authentication
string html;
using (WebClient client = new WebClient()) 
{
    // Add authentication headers if needed
    client.Headers.Add("Authorization", "Bearer " + accessToken);

    // Download the HTML string
    html = client.DownloadString("http://www.example.com/protected-content");
}

// Load the HTML into an HtmlDocument for parsing
HtmlDocument doc = new HtmlDocument();        
doc.LoadHtml(html);

// Extract all image sources for downloading
foreach(HtmlNode img in doc.DocumentNode.SelectNodes("//img")) 
{
    string imgSrc = img.GetAttributeValue("src", null);
    Console.WriteLine($"Found image: {imgSrc}");

    // Download each image asset
    if (!string.IsNullOrEmpty(imgSrc))
    {
        string fileName = Path.GetFileName(imgSrc);
        client.DownloadFile(imgSrc, fileName);
    }
}

// Convert the downloaded HTML to PDF
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("authenticated-content.pdf");
// Download HTML content from a URL with authentication
string html;
using (WebClient client = new WebClient()) 
{
    // Add authentication headers if needed
    client.Headers.Add("Authorization", "Bearer " + accessToken);

    // Download the HTML string
    html = client.DownloadString("http://www.example.com/protected-content");
}

// Load the HTML into an HtmlDocument for parsing
HtmlDocument doc = new HtmlDocument();        
doc.LoadHtml(html);

// Extract all image sources for downloading
foreach(HtmlNode img in doc.DocumentNode.SelectNodes("//img")) 
{
    string imgSrc = img.GetAttributeValue("src", null);
    Console.WriteLine($"Found image: {imgSrc}");

    // Download each image asset
    if (!string.IsNullOrEmpty(imgSrc))
    {
        string fileName = Path.GetFileName(imgSrc);
        client.DownloadFile(imgSrc, fileName);
    }
}

// Convert the downloaded HTML to PDF
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("authenticated-content.pdf");
Imports System.Net
Imports HtmlAgilityPack
Imports IronPdf

' Download HTML content from a URL with authentication
Dim html As String
Using client As New WebClient()
    ' Add authentication headers if needed
    client.Headers.Add("Authorization", "Bearer " & accessToken)

    ' Download the HTML string
    html = client.DownloadString("http://www.example.com/protected-content")
End Using

' Load the HTML into an HtmlDocument for parsing
Dim doc As New HtmlDocument()
doc.LoadHtml(html)

' Extract all image sources for downloading
For Each img As HtmlNode In doc.DocumentNode.SelectNodes("//img")
    Dim imgSrc As String = img.GetAttributeValue("src", Nothing)
    Console.WriteLine($"Found image: {imgSrc}")

    ' Download each image asset
    If Not String.IsNullOrEmpty(imgSrc) Then
        Dim fileName As String = Path.GetFileName(imgSrc)
        Using client As New WebClient()
            client.DownloadFile(imgSrc, fileName)
        End Using
    End If
Next

' Convert the downloaded HTML to PDF
Dim renderer As New ChromePdfRenderer()
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("authenticated-content.pdf")
$vbLabelText   $csharpLabel

請注意使用重載的 System.Uri 建構子將相對 URL 重新定位為絕對 URL。 若要重新定義 HTML 文件中的所有相對路徑,請使用 HtmlAgilityPack 將 <base> 標籤新增至標頭。 例子。 有關處理 URL 和資源的更多信息,請參閱"基本 URL 和資源編碼"指南

為什麼需要先下載HTML內容?

轉換前下載HTML內容有以下幾個優點:

1.完全控制:轉換前可修改 HTML、修復失效連結或註入身份驗證令牌
2.資源管理:下載並快取外部資源,例如映像、CSS 和JavaScript文件
3.身份驗證彈性:可使用任何.NET身份驗證機制,包括 OAuth、JWT 令牌或自訂標頭。
4.效能:快取常用內容以降低伺服器負載
5.調試:檢查正在轉換的確切 HTML 程式碼以排查問題。

對於涉及 cookie 和會話的複雜驗證場景,請參閱Cookie 指南,其中解釋了 PDF 轉換期間的驗證狀態管理。

如何處理圖片和樣式表等資源?

轉換已認證頁面時,外部資源通常也需要相同的認證。 以下是使用 HttpClient 的全面方法:

public async Task<string> DownloadAuthenticatedHtmlWithAssets(string url, string authToken)
{
    using (var client = new HttpClient())
    {
        // Set authentication header
        client.DefaultRequestHeaders.Authorization = 
            new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", authToken);

        // Download the main HTML
        string html = await client.GetStringAsync(url);

        // Parse HTML to find assets
        var doc = new HtmlDocument();
        doc.LoadHtml(html);

        // Create a base URI for resolving relative paths
        var baseUri = new Uri(url);

        // Download CSS files
        var cssLinks = doc.DocumentNode.SelectNodes("//link[@rel='stylesheet']");
        if (cssLinks != null)
        {
            foreach (var link in cssLinks)
            {
                string href = link.GetAttributeValue("href", "");
                if (!string.IsNullOrEmpty(href))
                {
                    var cssUri = new Uri(baseUri, href);
                    string cssContent = await client.GetStringAsync(cssUri);

                    // Embed CSS directly in the HTML
                    var styleNode = doc.CreateElement("style");
                    styleNode.InnerHtml = cssContent;
                    doc.DocumentNode.SelectSingleNode("//head").AppendChild(styleNode);

                    // Remove the external link
                    link.Remove();
                }
            }
        }

        // Return the modified HTML with embedded assets
        return doc.DocumentNode.OuterHtml;
    }
}
public async Task<string> DownloadAuthenticatedHtmlWithAssets(string url, string authToken)
{
    using (var client = new HttpClient())
    {
        // Set authentication header
        client.DefaultRequestHeaders.Authorization = 
            new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", authToken);

        // Download the main HTML
        string html = await client.GetStringAsync(url);

        // Parse HTML to find assets
        var doc = new HtmlDocument();
        doc.LoadHtml(html);

        // Create a base URI for resolving relative paths
        var baseUri = new Uri(url);

        // Download CSS files
        var cssLinks = doc.DocumentNode.SelectNodes("//link[@rel='stylesheet']");
        if (cssLinks != null)
        {
            foreach (var link in cssLinks)
            {
                string href = link.GetAttributeValue("href", "");
                if (!string.IsNullOrEmpty(href))
                {
                    var cssUri = new Uri(baseUri, href);
                    string cssContent = await client.GetStringAsync(cssUri);

                    // Embed CSS directly in the HTML
                    var styleNode = doc.CreateElement("style");
                    styleNode.InnerHtml = cssContent;
                    doc.DocumentNode.SelectSingleNode("//head").AppendChild(styleNode);

                    // Remove the external link
                    link.Remove();
                }
            }
        }

        // Return the modified HTML with embedded assets
        return doc.DocumentNode.OuterHtml;
    }
}
Imports System
Imports System.Net.Http
Imports System.Threading.Tasks
Imports HtmlAgilityPack

Public Class HtmlDownloader
    Public Async Function DownloadAuthenticatedHtmlWithAssets(url As String, authToken As String) As Task(Of String)
        Using client As New HttpClient()
            ' Set authentication header
            client.DefaultRequestHeaders.Authorization = New System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", authToken)

            ' Download the main HTML
            Dim html As String = Await client.GetStringAsync(url)

            ' Parse HTML to find assets
            Dim doc As New HtmlDocument()
            doc.LoadHtml(html)

            ' Create a base URI for resolving relative paths
            Dim baseUri As New Uri(url)

            ' Download CSS files
            Dim cssLinks = doc.DocumentNode.SelectNodes("//link[@rel='stylesheet']")
            If cssLinks IsNot Nothing Then
                For Each link In cssLinks
                    Dim href As String = link.GetAttributeValue("href", "")
                    If Not String.IsNullOrEmpty(href) Then
                        Dim cssUri As New Uri(baseUri, href)
                        Dim cssContent As String = Await client.GetStringAsync(cssUri)

                        ' Embed CSS directly in the HTML
                        Dim styleNode = doc.CreateElement("style")
                        styleNode.InnerHtml = cssContent
                        doc.DocumentNode.SelectSingleNode("//head").AppendChild(styleNode)

                        ' Remove the external link
                        link.Remove()
                    End If
                Next
            End If

            ' Return the modified HTML with embedded assets
            Return doc.DocumentNode.OuterHtml
        End Using
    End Function
End Class
$vbLabelText   $csharpLabel

哪些工具可以幫助解析HTML?

HtmlAgilityPack 是.NET中最受歡迎的 HTML 解析庫,但也有其他替代方案:

  1. HtmlAgilityPack :最適合通用的 HTML 解析與操作
  2. AngleSharp :一款現代化的、符合標準的 HTML 解析器,支援 CSS 選擇器
  3. CsQuery :針對熟悉 jQuery 的 C# 開發人員的類似 jQuery 的語法
    4.正規表示式:適用於簡單的提取任務(不建議用於複雜的 HTML)

如何使用網路身份驗證登入?

大多數ASP.NET應用程式支援網頁驗證,比 HTML 表單提交更可靠。 IronPDF透過 ChromeHttpLoginCredentials 類別提供基本驗證、摘要驗證和 NTLM 驗證的內建支援。 有關更多標頭自訂訊息,請參閱HTTP 請求標頭指南

:path=/static-assets/pdf/content-code-examples/how-to/logins-username-password.cs
using IronPdf;
using System;

ChromePdfRenderer renderer = new ChromePdfRenderer
{
    // setting login credentials to bypass basic authentication
    LoginCredentials = new ChromeHttpLoginCredentials()
    {
        NetworkUsername = "testUser",
        NetworkPassword = "testPassword"
    }
};

var uri = new Uri("http://localhost:51169/Invoice");

// Render web URL to PDF
PdfDocument pdf = renderer.RenderUrlAsPdf(uri);

// Export PDF
pdf.SaveAs("UrlToPdfExample.Pdf");
Imports IronPdf
Imports System

Private renderer As New ChromePdfRenderer With {
	.LoginCredentials = New ChromeHttpLoginCredentials() With {
		.NetworkUsername = "testUser",
		.NetworkPassword = "testPassword"
	}
}

Private uri = New Uri("http://localhost:51169/Invoice")

' Render web URL to PDF
Private pdf As PdfDocument = renderer.RenderUrlAsPdf(uri)

' Export PDF
pdf.SaveAs("UrlToPdfExample.Pdf")
$vbLabelText   $csharpLabel

為什麼網路認證比表單提交更可靠?

與HTML表單提交相比,網路身分驗證具有以下幾個優點:

1.標準化協定:使用符合 RFC 標準的 HTTP 驗證標頭
2.瀏覽器整合:Chrome 渲染引擎可無縫處理身份驗證。
3.會話管理:自動處理身份驗證挑戰和會話持久性
4.安全性:憑證透過標頭而非表單資料安全傳輸。
5.相容性:可與大多數企業驗證系統搭配使用(Active Directory, LDAP)

我需要哪些憑證才能進行網路身份驗證?

不同的身份驗證類型需要不同的憑證:

// Basic Authentication (most common)
var basicAuth = new ChromeHttpLoginCredentials
{
    NetworkUsername = "user@domain.com",
    NetworkPassword = "password123",
    AuthenticationType = ChromeHttpLoginCredentials.AuthType.Basic
};

// NTLM/Windows Authentication
var ntlmAuth = new ChromeHttpLoginCredentials
{
    NetworkUsername = "DOMAIN\\username", // Include domain
    NetworkPassword = "password123",
    AuthenticationType = ChromeHttpLoginCredentials.AuthType.Ntlm
};

// Custom authentication headers
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.CustomHttpHeaders.Add("X-API-Key", "your-api-key");
renderer.RenderingOptions.CustomHttpHeaders.Add("Authorization", "Bearer " + jwtToken);
// Basic Authentication (most common)
var basicAuth = new ChromeHttpLoginCredentials
{
    NetworkUsername = "user@domain.com",
    NetworkPassword = "password123",
    AuthenticationType = ChromeHttpLoginCredentials.AuthType.Basic
};

// NTLM/Windows Authentication
var ntlmAuth = new ChromeHttpLoginCredentials
{
    NetworkUsername = "DOMAIN\\username", // Include domain
    NetworkPassword = "password123",
    AuthenticationType = ChromeHttpLoginCredentials.AuthType.Ntlm
};

// Custom authentication headers
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.CustomHttpHeaders.Add("X-API-Key", "your-api-key");
renderer.RenderingOptions.CustomHttpHeaders.Add("Authorization", "Bearer " + jwtToken);
Imports System.Collections.Generic

' Basic Authentication (most common)
Dim basicAuth As New ChromeHttpLoginCredentials With {
    .NetworkUsername = "user@domain.com",
    .NetworkPassword = "password123",
    .AuthenticationType = ChromeHttpLoginCredentials.AuthType.Basic
}

' NTLM/Windows Authentication
Dim ntlmAuth As New ChromeHttpLoginCredentials With {
    .NetworkUsername = "DOMAIN\username", ' Include domain
    .NetworkPassword = "password123",
    .AuthenticationType = ChromeHttpLoginCredentials.AuthType.Ntlm
}

' Custom authentication headers
Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.CustomHttpHeaders.Add("X-API-Key", "your-api-key")
renderer.RenderingOptions.CustomHttpHeaders.Add("Authorization", "Bearer " & jwtToken)
$vbLabelText   $csharpLabel

如何排除身份驗證失敗問題?

常見身分驗證問題及解決方案:

  1. 401 未授權:檢查憑證和驗證類型
  2. 403 禁止存取:使用者已通過身份驗證,但缺少權限
    3.逾時錯誤:對於速度較慢的身份驗證系統,請增加 RenderDelay
    4.憑證錯誤:請正確設定 TLS/SSL 設定

啟用調試功能以診斷問題:

// Enable detailed logging
IronPdf.Logging.Logger.EnableDebugging = true;
IronPdf.Logging.Logger.LogFilePath = "IronPdf.log";
IronPdf.Logging.Logger.LoggingMode = IronPdf.Logging.Logger.LoggingModes.All;

// Test authentication
try 
{
    var pdf = renderer.RenderUrlAsPdf("https://secure.example.com");
    pdf.SaveAs("authenticated.pdf");
}
catch (Exception ex)
{
    Console.WriteLine($"Authentication failed: {ex.Message}");
    // Check IronPdf.log for detailed error information
}
// Enable detailed logging
IronPdf.Logging.Logger.EnableDebugging = true;
IronPdf.Logging.Logger.LogFilePath = "IronPdf.log";
IronPdf.Logging.Logger.LoggingMode = IronPdf.Logging.Logger.LoggingModes.All;

// Test authentication
try 
{
    var pdf = renderer.RenderUrlAsPdf("https://secure.example.com");
    pdf.SaveAs("authenticated.pdf");
}
catch (Exception ex)
{
    Console.WriteLine($"Authentication failed: {ex.Message}");
    // Check IronPdf.log for detailed error information
}
Imports IronPdf
Imports System

' Enable detailed logging
Logging.Logger.EnableDebugging = True
Logging.Logger.LogFilePath = "IronPdf.log"
Logging.Logger.LoggingMode = Logging.Logger.LoggingModes.All

' Test authentication
Try
    Dim pdf = renderer.RenderUrlAsPdf("https://secure.example.com")
    pdf.SaveAs("authenticated.pdf")
Catch ex As Exception
    Console.WriteLine($"Authentication failed: {ex.Message}")
    ' Check IronPdf.log for detailed error information
End Try
$vbLabelText   $csharpLabel

如何使用HTML表單登入?

若要透過向 HTML 表單傳送資料進行登錄,請使用ChromeHttpLoginCredentials類別。 請參閱 IronPDF 的ChromeHttpLoginCredentials API

請考慮以下幾點:

  • 將登入資料傳送至 HTML 表單 ACTION 屬性中指定的 URL。 將此設定為 HttpLoginCredentials 的 LoginFormUrl 屬性。 這可能與您想要渲染成 PDF 的 URL 不同。
  • 傳送代表 HTML 表單中每個輸入框和文字區域的資料。 name 屬性定義了每個變數的名稱(而不是 id)。
    有些網站會主動採取措施防止機器登入。

以下是一個完整的基於表單的身份驗證範例:

// Configure form-based login
var formLogin = new ChromeHttpLoginCredentials
{
    LoginFormUrl = "https://example.com/login",
    LoginFormData = new Dictionary<string, string>
    {
        {"username", "user@example.com"},
        {"password", "securePassword123"},
        {"rememberMe", "true"},
        {"csrf_token", "abc123"} // Include any hidden fields
    }
};

var renderer = new ChromePdfRenderer
{
    LoginCredentials = formLogin,
    RenderingOptions = new ChromePdfRenderOptions
    {
        RenderDelay = 3000, // Allow time for login redirect
        EnableJavaScript = true
    }
};

// The actual page you want to convert (after login)
var pdf = renderer.RenderUrlAsPdf("https://example.com/dashboard");
pdf.SaveAs("dashboard.pdf");
// Configure form-based login
var formLogin = new ChromeHttpLoginCredentials
{
    LoginFormUrl = "https://example.com/login",
    LoginFormData = new Dictionary<string, string>
    {
        {"username", "user@example.com"},
        {"password", "securePassword123"},
        {"rememberMe", "true"},
        {"csrf_token", "abc123"} // Include any hidden fields
    }
};

var renderer = new ChromePdfRenderer
{
    LoginCredentials = formLogin,
    RenderingOptions = new ChromePdfRenderOptions
    {
        RenderDelay = 3000, // Allow time for login redirect
        EnableJavaScript = true
    }
};

// The actual page you want to convert (after login)
var pdf = renderer.RenderUrlAsPdf("https://example.com/dashboard");
pdf.SaveAs("dashboard.pdf");
Imports System.Collections.Generic

' Configure form-based login
Dim formLogin As New ChromeHttpLoginCredentials With {
    .LoginFormUrl = "https://example.com/login",
    .LoginFormData = New Dictionary(Of String, String) From {
        {"username", "user@example.com"},
        {"password", "securePassword123"},
        {"rememberMe", "true"},
        {"csrf_token", "abc123"} ' Include any hidden fields
    }
}

Dim renderer As New ChromePdfRenderer With {
    .LoginCredentials = formLogin,
    .RenderingOptions = New ChromePdfRenderOptions With {
        .RenderDelay = 3000, ' Allow time for login redirect
        .EnableJavaScript = True
    }
}

' The actual page you want to convert (after login)
Dim pdf = renderer.RenderUrlAsPdf("https://example.com/dashboard")
pdf.SaveAs("dashboard.pdf")
$vbLabelText   $csharpLabel

我需要收集哪些表單資料?

若要透過 HTML 表單成功進行驗證,請擷取所有表單輸入:

// Use this helper method to extract form fields
public Dictionary<string, string> ExtractFormFields(string loginPageHtml)
{
    var formData = new Dictionary<string, string>();
    var doc = new HtmlDocument();
    doc.LoadHtml(loginPageHtml);

    // Find all input fields
    var inputs = doc.DocumentNode.SelectNodes("//input");
    if (inputs != null)
    {
        foreach (var input in inputs)
        {
            string name = input.GetAttributeValue("name", "");
            string value = input.GetAttributeValue("value", "");
            string type = input.GetAttributeValue("type", "text");

            if (!string.IsNullOrEmpty(name))
            {
                // Handle different input types
                switch (type.ToLower())
                {
                    case "checkbox":
                        if (input.Attributes["checked"] != null)
                            formData[name] = "on";
                        break;
                    case "radio":
                        if (input.Attributes["checked"] != null)
                            formData[name] = value;
                        break;
                    default:
                        formData[name] = value;
                        break;
                }
            }
        }
    }

    // Don't forget select elements
    var selects = doc.DocumentNode.SelectNodes("//select");
    if (selects != null)
    {
        foreach (var select in selects)
        {
            string name = select.GetAttributeValue("name", "");
            var selected = select.SelectSingleNode(".//option[@selected]");
            if (selected != null && !string.IsNullOrEmpty(name))
            {
                formData[name] = selected.GetAttributeValue("value", "");
            }
        }
    }

    return formData;
}
// Use this helper method to extract form fields
public Dictionary<string, string> ExtractFormFields(string loginPageHtml)
{
    var formData = new Dictionary<string, string>();
    var doc = new HtmlDocument();
    doc.LoadHtml(loginPageHtml);

    // Find all input fields
    var inputs = doc.DocumentNode.SelectNodes("//input");
    if (inputs != null)
    {
        foreach (var input in inputs)
        {
            string name = input.GetAttributeValue("name", "");
            string value = input.GetAttributeValue("value", "");
            string type = input.GetAttributeValue("type", "text");

            if (!string.IsNullOrEmpty(name))
            {
                // Handle different input types
                switch (type.ToLower())
                {
                    case "checkbox":
                        if (input.Attributes["checked"] != null)
                            formData[name] = "on";
                        break;
                    case "radio":
                        if (input.Attributes["checked"] != null)
                            formData[name] = value;
                        break;
                    default:
                        formData[name] = value;
                        break;
                }
            }
        }
    }

    // Don't forget select elements
    var selects = doc.DocumentNode.SelectNodes("//select");
    if (selects != null)
    {
        foreach (var select in selects)
        {
            string name = select.GetAttributeValue("name", "");
            var selected = select.SelectSingleNode(".//option[@selected]");
            if (selected != null && !string.IsNullOrEmpty(name))
            {
                formData[name] = selected.GetAttributeValue("value", "");
            }
        }
    }

    return formData;
}
Imports HtmlAgilityPack

Public Function ExtractFormFields(loginPageHtml As String) As Dictionary(Of String, String)
    Dim formData As New Dictionary(Of String, String)()
    Dim doc As New HtmlDocument()
    doc.LoadHtml(loginPageHtml)

    ' Find all input fields
    Dim inputs = doc.DocumentNode.SelectNodes("//input")
    If inputs IsNot Nothing Then
        For Each input In inputs
            Dim name As String = input.GetAttributeValue("name", "")
            Dim value As String = input.GetAttributeValue("value", "")
            Dim type As String = input.GetAttributeValue("type", "text")

            If Not String.IsNullOrEmpty(name) Then
                ' Handle different input types
                Select Case type.ToLower()
                    Case "checkbox"
                        If input.Attributes("checked") IsNot Nothing Then
                            formData(name) = "on"
                        End If
                    Case "radio"
                        If input.Attributes("checked") IsNot Nothing Then
                            formData(name) = value
                        End If
                    Case Else
                        formData(name) = value
                End Select
            End If
        Next
    End If

    ' Don't forget select elements
    Dim selects = doc.DocumentNode.SelectNodes("//select")
    If selects IsNot Nothing Then
        For Each selectNode In selects
            Dim name As String = selectNode.GetAttributeValue("name", "")
            Dim selected = selectNode.SelectSingleNode(".//option[@selected]")
            If selected IsNot Nothing AndAlso Not String.IsNullOrEmpty(name) Then
                formData(name) = selected.GetAttributeValue("value", "")
            End If
        Next
    End If

    Return formData
End Function
$vbLabelText   $csharpLabel

如何找到正確的表單操作 URL?

表單操作 URL 對於成功進行身份驗證至關重要:

public string ExtractFormAction(string loginPageUrl, string loginPageHtml)
{
    var doc = new HtmlDocument();
    doc.LoadHtml(loginPageHtml);

    // Find the login form
    var form = doc.DocumentNode.SelectSingleNode("//form[contains(@action, 'login') or contains(@id, 'login') or contains(@class, 'login')]");

    if (form == null)
    {
        // Try finding any form with password field
        form = doc.DocumentNode.SelectSingleNode("//form[.//input[@type='password']]");
    }

    if (form != null)
    {
        string action = form.GetAttributeValue("action", "");

        // Resolve relative URLs
        if (!string.IsNullOrEmpty(action))
        {
            var baseUri = new Uri(loginPageUrl);
            var actionUri = new Uri(baseUri, action);
            return actionUri.ToString();
        }
    }

    // Default to the login page URL if no action found
    return loginPageUrl;
}
public string ExtractFormAction(string loginPageUrl, string loginPageHtml)
{
    var doc = new HtmlDocument();
    doc.LoadHtml(loginPageHtml);

    // Find the login form
    var form = doc.DocumentNode.SelectSingleNode("//form[contains(@action, 'login') or contains(@id, 'login') or contains(@class, 'login')]");

    if (form == null)
    {
        // Try finding any form with password field
        form = doc.DocumentNode.SelectSingleNode("//form[.//input[@type='password']]");
    }

    if (form != null)
    {
        string action = form.GetAttributeValue("action", "");

        // Resolve relative URLs
        if (!string.IsNullOrEmpty(action))
        {
            var baseUri = new Uri(loginPageUrl);
            var actionUri = new Uri(baseUri, action);
            return actionUri.ToString();
        }
    }

    // Default to the login page URL if no action found
    return loginPageUrl;
}
Imports System

Public Function ExtractFormAction(loginPageUrl As String, loginPageHtml As String) As String
    Dim doc As New HtmlDocument()
    doc.LoadHtml(loginPageHtml)

    ' Find the login form
    Dim form = doc.DocumentNode.SelectSingleNode("//form[contains(@action, 'login') or contains(@id, 'login') or contains(@class, 'login')]")

    If form Is Nothing Then
        ' Try finding any form with password field
        form = doc.DocumentNode.SelectSingleNode("//form[.//input[@type='password']]")
    End If

    If form IsNot Nothing Then
        Dim action As String = form.GetAttributeValue("action", "")

        ' Resolve relative URLs
        If Not String.IsNullOrEmpty(action) Then
            Dim baseUri As New Uri(loginPageUrl)
            Dim actionUri As New Uri(baseUri, action)
            Return actionUri.ToString()
        End If
    End If

    ' Default to the login page URL if no action found
    Return loginPageUrl
End Function
$vbLabelText   $csharpLabel

基於表單的身份驗證有哪些常見問題?

  1. CSRF 令牌:許多表單都包含防偽令牌,這些令牌會過期。
  2. JavaScript驗證:某些表單需要執行JavaScript。 3.多步驟身份驗證:需要多個頁面的表單
    4.驗證碼保護:手動驗證挑戰
    5.會話逾時:登入會話快速過期。

我該如何進行反機器人保護?

現代網站都採取了防止自動登入的保護措施:

// Strategies for handling anti-bot measures
var renderer = new ChromePdfRenderer
{
    RenderingOptions = new ChromePdfRenderOptions
    {
        // Mimic real browser behavior
        ViewPortWidth = 1920,
        ViewPortHeight = 1080,
        EnableJavaScript = true,
        RenderDelay = 5000, // Wait for JavaScript

        // Set a real user agent
        CustomHttpHeaders = new Dictionary<string, string>
        {
            {"User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"}
        }
    }
};

 // For sites with rate limiting, add delays between requests
 System.Threading.Thread.Sleep(2000);
// Strategies for handling anti-bot measures
var renderer = new ChromePdfRenderer
{
    RenderingOptions = new ChromePdfRenderOptions
    {
        // Mimic real browser behavior
        ViewPortWidth = 1920,
        ViewPortHeight = 1080,
        EnableJavaScript = true,
        RenderDelay = 5000, // Wait for JavaScript

        // Set a real user agent
        CustomHttpHeaders = new Dictionary<string, string>
        {
            {"User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"}
        }
    }
};

 // For sites with rate limiting, add delays between requests
 System.Threading.Thread.Sleep(2000);
' Strategies for handling anti-bot measures
Dim renderer = New ChromePdfRenderer With {
    .RenderingOptions = New ChromePdfRenderOptions With {
        ' Mimic real browser behavior
        .ViewPortWidth = 1920,
        .ViewPortHeight = 1080,
        .EnableJavaScript = True,
        .RenderDelay = 5000, ' Wait for JavaScript

        ' Set a real user agent
        .CustomHttpHeaders = New Dictionary(Of String, String) From {
            {"User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"}
        }
    }
}

' For sites with rate limiting, add delays between requests
System.Threading.Thread.Sleep(2000)
$vbLabelText   $csharpLabel

有關 HTML 到 PDF 轉換的全面指南,包括複雜的身份驗證場景,請造訪HTML 到 PDF 教學

如何處理 MVC 驗證?

以下解決方法透過程式設計方式將.NET MVC 視圖渲染為字串,從而避免 MVC 登錄,同時忠實渲染視圖。 在 MVC Core 或MVC Framework中將 CSHTML 轉換為 PDF時,這種方法效果很好。

// Converts an MVC partial view to a string
public static string RenderPartialViewToString(this Controller controller, string viewPath, object model = null)
{
    try
    {
        // Set the model
        var context = controller.ControllerContext;
        controller.ViewData.Model = model;

        using (var sw = new StringWriter())
        {
            // Find the partial view
            var viewResult = ViewEngines.Engines.FindPartialView(context, viewPath);

            if (viewResult.View == null)
            {
                throw new Exception($"Partial view {viewPath} could not be found.");
            }

            // Create a view context
            var viewContext = new ViewContext(context, viewResult.View, context.Controller.ViewData, context.Controller.TempData, sw);

            // Render the view
            viewResult.View.Render(viewContext, sw);
            viewResult.ViewEngine.ReleaseView(context, viewResult.View);

            return sw.GetStringBuilder().ToString();
        }
    }
    catch (Exception ex)
    {
        // Return error message if there is an exception
        return ex.Message;
    }
}

// Usage in an MVC Controller
public ActionResult GeneratePdf()
{
    // Render authenticated view to string
    var model = new InvoiceViewModel { /* populate model */ };
    string html = this.RenderPartialViewToString("~/Views/Invoice/Details.cshtml", model);

    // Convert to PDF
    var renderer = new ChromePdfRenderer();
    var pdf = renderer.RenderHtmlAsPdf(html);

    // Return PDF file
    return File(pdf.BinaryData, "application/pdf", "invoice.pdf");
}
// Converts an MVC partial view to a string
public static string RenderPartialViewToString(this Controller controller, string viewPath, object model = null)
{
    try
    {
        // Set the model
        var context = controller.ControllerContext;
        controller.ViewData.Model = model;

        using (var sw = new StringWriter())
        {
            // Find the partial view
            var viewResult = ViewEngines.Engines.FindPartialView(context, viewPath);

            if (viewResult.View == null)
            {
                throw new Exception($"Partial view {viewPath} could not be found.");
            }

            // Create a view context
            var viewContext = new ViewContext(context, viewResult.View, context.Controller.ViewData, context.Controller.TempData, sw);

            // Render the view
            viewResult.View.Render(viewContext, sw);
            viewResult.ViewEngine.ReleaseView(context, viewResult.View);

            return sw.GetStringBuilder().ToString();
        }
    }
    catch (Exception ex)
    {
        // Return error message if there is an exception
        return ex.Message;
    }
}

// Usage in an MVC Controller
public ActionResult GeneratePdf()
{
    // Render authenticated view to string
    var model = new InvoiceViewModel { /* populate model */ };
    string html = this.RenderPartialViewToString("~/Views/Invoice/Details.cshtml", model);

    // Convert to PDF
    var renderer = new ChromePdfRenderer();
    var pdf = renderer.RenderHtmlAsPdf(html);

    // Return PDF file
    return File(pdf.BinaryData, "application/pdf", "invoice.pdf");
}
Imports System
Imports System.IO
Imports System.Web.Mvc
Imports IronPdf

' Converts an MVC partial view to a string
Public Module ControllerExtensions
    <System.Runtime.CompilerServices.Extension>
    Public Function RenderPartialViewToString(controller As Controller, viewPath As String, Optional model As Object = Nothing) As String
        Try
            ' Set the model
            Dim context = controller.ControllerContext
            controller.ViewData.Model = model

            Using sw As New StringWriter()
                ' Find the partial view
                Dim viewResult = ViewEngines.Engines.FindPartialView(context, viewPath)

                If viewResult.View Is Nothing Then
                    Throw New Exception($"Partial view {viewPath} could not be found.")
                End If

                ' Create a view context
                Dim viewContext As New ViewContext(context, viewResult.View, context.Controller.ViewData, context.Controller.TempData, sw)

                ' Render the view
                viewResult.View.Render(viewContext, sw)
                viewResult.ViewEngine.ReleaseView(context, viewResult.View)

                Return sw.GetStringBuilder().ToString()
            End Using
        Catch ex As Exception
            ' Return error message if there is an exception
            Return ex.Message
        End Try
    End Function
End Module

' Usage in an MVC Controller
Public Class InvoiceController
    Inherits Controller

    Public Function GeneratePdf() As ActionResult
        ' Render authenticated view to string
        Dim model As New InvoiceViewModel() ' populate model
        Dim html As String = Me.RenderPartialViewToString("~/Views/Invoice/Details.cshtml", model)

        ' Convert to PDF
        Dim renderer As New ChromePdfRenderer()
        Dim pdf = renderer.RenderHtmlAsPdf(html)

        ' Return PDF file
        Return File(pdf.BinaryData, "application/pdf", "invoice.pdf")
    End Function
End Class
$vbLabelText   $csharpLabel

為什麼將視圖渲染為字串而不是直接轉換?

將 MVC 視圖渲染為字串具有以下幾個主要優勢:

1.身份驗證上下文:視圖在已驗證使用者的上下文中呈現
2.完整的 MVC 管道:所有 MVC 功能均可正常運作,包括 TempDataHtml 輔助函數
3.佈局支援:母版頁和佈局能夠正確渲染。
4.模型綁定:複雜的視圖模型可以無縫協作
5.操作過濾器:安全性和日誌過濾器正常執行

這種 MVC 變通方案有什麼好處?

MVC字串渲染方法具有以下優點:

-安全性:無需暴露內部 URL 或繞過身份驗證
-效能:避免額外的 HTTP 請求
-一致性:輸出結果與使用者在瀏覽器中看到的結果完全一致
-靈活性:可在轉換為 PDF 之前修改 HTML
-測試:輕鬆產生單元測試 HTML

如何將模型傳遞給渲染視圖?

以下是一個包含複雜模型的全面範例:

public class InvoiceController : Controller
{
    private readonly IInvoiceService _invoiceService;

    public async Task<ActionResult> DownloadInvoicePdf(int invoiceId)
    {
        // Load data within authenticated context
        var invoice = await _invoiceService.GetInvoiceAsync(invoiceId);

        if (invoice == null || invoice.UserId != User.Identity.GetUserId())
        {
            return HttpNotFound();
        }

        // Create view model
        var viewModel = new InvoiceDetailsViewModel
        {
            Invoice = invoice,
            Company = await _invoiceService.GetCompanyDetailsAsync(),
            LineItems = await _invoiceService.GetLineItemsAsync(invoiceId),
            TaxDetails = await _invoiceService.GetTaxDetailsAsync(invoiceId)
        };

        // Render to HTML string
        string html = this.RenderPartialViewToString("~/Views/Invoice/DetailsPdf.cshtml", viewModel);

        // Add custom styling for PDF
        html = $@"
            <html>
            <head>
                <style>
                    body {{ font-family: Arial, sans-serif; }}
                    .invoice-header {{ background-color: #f0f0f0; padding: 20px; }}
                    .line-items {{ width: 100%; border-collapse: collapse; }}
                    .line-items th, .line-items td {{ border: 1px solid #ddd; padding: 8px; }}
                </style>
            </head>
            <body>
                {html}
            </body>
            </html>";

        // Convert to PDF with options
        var renderer = new ChromePdfRenderer
        {
            RenderingOptions = new ChromePdfRenderOptions
            {
                MarginTop = 20,
                MarginBottom = 20,
                MarginLeft = 10,
                MarginRight = 10,
                PrintHtmlBackgrounds = true
            }
        };

        var pdf = renderer.RenderHtmlAsPdf(html);

        // Add metadata
        pdf.MetaData.Author = "Invoice System";
        pdf.MetaData.Title = $"Invoice #{invoice.Number}";
        pdf.MetaData.CreationDate = DateTime.Now;

        return File(pdf.BinaryData, "application/pdf", $"Invoice-{invoice.Number}.pdf");
    }
}
public class InvoiceController : Controller
{
    private readonly IInvoiceService _invoiceService;

    public async Task<ActionResult> DownloadInvoicePdf(int invoiceId)
    {
        // Load data within authenticated context
        var invoice = await _invoiceService.GetInvoiceAsync(invoiceId);

        if (invoice == null || invoice.UserId != User.Identity.GetUserId())
        {
            return HttpNotFound();
        }

        // Create view model
        var viewModel = new InvoiceDetailsViewModel
        {
            Invoice = invoice,
            Company = await _invoiceService.GetCompanyDetailsAsync(),
            LineItems = await _invoiceService.GetLineItemsAsync(invoiceId),
            TaxDetails = await _invoiceService.GetTaxDetailsAsync(invoiceId)
        };

        // Render to HTML string
        string html = this.RenderPartialViewToString("~/Views/Invoice/DetailsPdf.cshtml", viewModel);

        // Add custom styling for PDF
        html = $@"
            <html>
            <head>
                <style>
                    body {{ font-family: Arial, sans-serif; }}
                    .invoice-header {{ background-color: #f0f0f0; padding: 20px; }}
                    .line-items {{ width: 100%; border-collapse: collapse; }}
                    .line-items th, .line-items td {{ border: 1px solid #ddd; padding: 8px; }}
                </style>
            </head>
            <body>
                {html}
            </body>
            </html>";

        // Convert to PDF with options
        var renderer = new ChromePdfRenderer
        {
            RenderingOptions = new ChromePdfRenderOptions
            {
                MarginTop = 20,
                MarginBottom = 20,
                MarginLeft = 10,
                MarginRight = 10,
                PrintHtmlBackgrounds = true
            }
        };

        var pdf = renderer.RenderHtmlAsPdf(html);

        // Add metadata
        pdf.MetaData.Author = "Invoice System";
        pdf.MetaData.Title = $"Invoice #{invoice.Number}";
        pdf.MetaData.CreationDate = DateTime.Now;

        return File(pdf.BinaryData, "application/pdf", $"Invoice-{invoice.Number}.pdf");
    }
}
Imports System.Threading.Tasks
Imports System.Web.Mvc

Public Class InvoiceController
    Inherits Controller

    Private ReadOnly _invoiceService As IInvoiceService

    Public Async Function DownloadInvoicePdf(invoiceId As Integer) As Task(Of ActionResult)
        ' Load data within authenticated context
        Dim invoice = Await _invoiceService.GetInvoiceAsync(invoiceId)

        If invoice Is Nothing OrElse invoice.UserId <> User.Identity.GetUserId() Then
            Return HttpNotFound()
        End If

        ' Create view model
        Dim viewModel As New InvoiceDetailsViewModel With {
            .Invoice = invoice,
            .Company = Await _invoiceService.GetCompanyDetailsAsync(),
            .LineItems = Await _invoiceService.GetLineItemsAsync(invoiceId),
            .TaxDetails = Await _invoiceService.GetTaxDetailsAsync(invoiceId)
        }

        ' Render to HTML string
        Dim html As String = Me.RenderPartialViewToString("~/Views/Invoice/DetailsPdf.cshtml", viewModel)

        ' Add custom styling for PDF
        html = $"
            <html>
            <head>
                <style>
                    body {{ font-family: Arial, sans-serif; }}
                    .invoice-header {{ background-color: #f0f0f0; padding: 20px; }}
                    .line-items {{ width: 100%; border-collapse: collapse; }}
                    .line-items th, .line-items td {{ border: 1px solid #ddd; padding: 8px; }}
                </style>
            </head>
            <body>
                {html}
            </body>
            </html>"

        ' Convert to PDF with options
        Dim renderer As New ChromePdfRenderer With {
            .RenderingOptions = New ChromePdfRenderOptions With {
                .MarginTop = 20,
                .MarginBottom = 20,
                .MarginLeft = 10,
                .MarginRight = 10,
                .PrintHtmlBackgrounds = True
            }
        }

        Dim pdf = renderer.RenderHtmlAsPdf(html)

        ' Add metadata
        pdf.MetaData.Author = "Invoice System"
        pdf.MetaData.Title = $"Invoice #{invoice.Number}"
        pdf.MetaData.CreationDate = DateTime.Now

        Return File(pdf.BinaryData, "application/pdf", $"Invoice-{invoice.Number}.pdf")
    End Function
End Class
$vbLabelText   $csharpLabel

在實施任何身份驗證解決方案之前,請確保已正確安裝IronPDF並配置了許可證金鑰。

準備好要看看你還能做什麼了嗎? 造訪我們的教學頁面:轉換 PDF

常見問題解答

當內容位於登入表單之後,我該如何將 HTML 轉換成 PDF?

IronPDF 提供了多種在登入驗證後將 HTML 轉換為 PDF 的方法。您可以使用 ChromeHttpLoginCredentials API 進行 TLS 網路驗證,或使用 System.Net.WebClient 或 HttpClient 下載 HTML 內容,並加上適當的驗證標頭,然後再使用 IronPDF 將其轉換為 PDF。

什麼是 ChromeHttpLoginCredentials?

ChromeHttpLoginCredentials 是 IronPDF 處理網路認證的 API。您可以通過在 ChromePdfRenderer 上的 LoginCredentials 屬性中設置您的用戶名和密碼來使用它,允許 IronPDF 在將受密碼保護的 URL 渲染成 PDF 時自動進行身份驗證。

我可以處理基於 HTML 表單的登入 PDF 轉換嗎?

是的,IronPDF 支持基于 HTML 表单的登录。建議的方法是使用 System.Net.WebClient 或 HttpClient 來處理登入過程,下載驗證的 HTML 內容,然後再使用 IronPDF 的 RenderHtmlAsPdf 方法將下載的 HTML 轉換成 PDF。

如何從驗證的頁面下載圖片和樣式表等 HTML 資產?

您可以使用 HtmlAgilityPack 來解析下載的 HTML 並擷取資產 URL,例如圖片和樣式表。然後使用 System.Net.WebClient 下載每個具有相同驗證標頭的資產,最後再使用 IronPDF 將完整的 HTML 套件轉換為 PDF。

處理認證標記或標頭的最佳做法是什麼?

使用 IronPDF 時,請使用 HttpClient 或 WebClient 下載 HTML,並附上驗證標頭(例如 Bearer tokens)。一旦您在記憶體或磁碟中儲存了認證的 HTML 內容,請使用 IronPDF 的 ChromePdfRenderer 將其轉換為 PDF。

MVC 登入驗證有變通的方法嗎?

是的,IronPDF 為 MVC 登入驗證情況提供了變通方案。建議的方法是先使用標準的 .NET HTTP 客戶端驗證和下載 HTML 內容,然後將驗證的 HTML 直接傳遞給 IronPDF 的渲染引擎,而不是由 IronPDF 處理驗證。

Curtis Chau
技術作家

Curtis Chau 擁有卡爾頓大學計算機科學學士學位,專注於前端開發,擅長於 Node.js、TypeScript、JavaScript 和 React。Curtis 熱衷於創建直觀且美觀的用戶界面,喜歡使用現代框架並打造結構良好、視覺吸引人的手冊。

除了開發之外,Curtis 對物聯網 (IoT) 有著濃厚的興趣,探索將硬體和軟體結合的創新方式。在閒暇時間,他喜愛遊戲並構建 Discord 機器人,結合科技與創意的樂趣。

準備好開始了嗎?
Nuget 下載 18,120,209 | 版本: 2026.4 剛剛發布
Still Scrolling Icon

還在捲動嗎?

想要快速證明? PM > Install-Package IronPdf
執行範例 觀看您的 HTML 變成 PDF。