【发布时间】:2014-08-23 05:41:22
【问题描述】:
我正在开发一个 Umbraco 内部网站,我在其中调用 wkhtmltopdf.exe 来创建一些 pdf。这些 pdf 使用一个主页作为内容,另外两个页面作为页眉和页脚。只要我拥有未经身份验证的网站,事情就可以很好地工作。我们想使用我们的 Active Directory 帐户登录到该站点,因此我启用了 Windows 身份验证。运行此程序的例程是单击处理页面的按钮,然后在浏览器上显示 pdf 或下载它。无论如何,这是相同的过程。在Visual Studio中,当涉及到代码的第一部分(var p = ...)运行调试时,它会抛出异常“消息=“没有进程与此对象关联。”因为它无法进行身份验证。我可以看到当我在代码执行后暂停代码并使用 Visual Studio 检查器时。该方法运行到最后,但由于我之前提到的错误,它会产生一个空白 pdf。如果我硬编码用户名和密码,那么它工作正常。
网站在 iis express 的本地开发环境中运行。由于在我第一次必须登录时浏览到该站点时启用了 Windows 身份验证。 Wkhtmltopdf.exe 位于本地驱动器中 - 它不在网站上。初始设置基于此处描述的方法http://icanmakethiswork.blogspot.se/2012/04/making-pdfs-from-html-in-c-using.html 只有属于我们的 Active Directory 域的用户才能访问该网站,但由于我们使用相同的帐户登录到 Windows,因此 Windows 身份验证将起到作用:)
public static void HtmlToPdf(string outputFilename, string[] urls,
string[] options = null,
bool streamPdf = false,
string pdfHtmlToPdfExePath = "C:\\Program Files (x86)\\wkhtmltopdf\\bin\\wkhtmltopdf.exe")
{
string urlsSeparatedBySpaces = string.Empty;
try
{
//Determine inputs
if ((urls == null) || (urls.Length == 0))
{
throw new Exception("No input URLs provided for HtmlToPdf");
}
urlsSeparatedBySpaces = String.Join(" ", urls); //Concatenate URLs
var p = new System.Diagnostics.Process()
{
StartInfo =
{
FileName = pdfHtmlToPdfExePath,
Arguments = ((options == null) ? "" : String.Join(" ", options)) + " " + urlsSeparatedBySpaces + " -",
UseShellExecute = false, // needs to be false in order to redirect output
RedirectStandardOutput = true,
RedirectStandardError = true,
RedirectStandardInput = true, // redirect all 3, as it should be all 3 or none
WorkingDirectory = string.Empty
}
};
p.Start();
var output = p.StandardOutput.ReadToEnd();
byte[] buffer = p.StandardOutput.CurrentEncoding.GetBytes(output);
p.WaitForExit(60000);
p.Close();
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ContentType = "application/pdf";
if (!streamPdf)
{
HttpContext.Current.Response.AppendHeader("Content-Disposition", "attachment; filename='" + outputFilename + "'");
}
HttpContext.Current.Response.BinaryWrite(buffer);
HttpContext.Current.Response.End();
}
catch (Exception exc)
{
throw new Exception("Problem generating PDF from HTML, URLs: " + urlsSeparatedBySpaces + ", outputFilename: " + outputFilename, exc);
}
}
我使用 LoadUserProfile = true 对此进行了测试,但这也无济于事。在阅读了各种论坛帖子之后,我看到的唯一建议的解决方案是使用用户名、密码等强制登录过程。但这很糟糕,因为用户已经登录,我们可以/应该使用像 CredentialCache.DefaultCredentials 这样的东西。
我也来的一个解决方法是在请求中使用 DefaultCredentials 在本地保存 html,我可以毫无问题地访问它们并创建 pdf,但即使这是一个艰苦的过程,因为我需要创建可打印的 css 和 javascripts 和下载它们等等。这是我最后一个解决方案,我已经实现了 80%,但看起来也很讨厌。这是我如何抓取网页的另一个代码示例。
var request = (HttpWebRequest)WebRequest.Create(url);
request.Credentials = CredentialCache.DefaultCredentials;
var response = (HttpWebResponse)request.GetResponse();
var stream = response.GetResponseStream();
总结一下。 Wkhtmltopdf 无法对自身进行身份验证,因此它可以获取所需的页面并将它们转换为 pdf。是否有任何巧妙的方法可以使该过程能够使用我登录到该站点的当前用户凭据对自身进行身份验证,以便它可以访问这些页面?
【问题讨论】:
-
我不完全理解整个场景。那么有访问网页的用户吗? wkhtmltopdf 在哪里运行?这是一个服务器组件还是在客户端上运行并访问网页?
-
抱歉,有些部分含糊不清。 Wkhtmltopdf.exe 位于本地驱动器中 - 它不在网站上。初始设置基于此处描述的方法icanmakethiswork.blogspot.se/2012/04/… 只有属于我们 Active Directory 域的用户才能访问该网站。希望我现在已经澄清了一点我的问题。
-
好的。现在我明白了。因此 Wkhtmltopdf.exe 在当前登录用户的上下文中运行。正确的?现在抛出什么类型的异常会很有趣
-
是的。它在我的本地开发环境中的 IIS.Express 下运行,显然“用户”与登录站点的实际用户不同。因此,进程崩溃,因为它无法访问网页来检索内容。
-
如果您在本地开发机器上运行所有内容(IIS express 网站以及未在其他用户下启动的 Wkhtmltopdf.exe),则用户是相同的。为了测试这一点,您可以开始例如calc.exe 然后打开任务管理器,您可以看到 IIS express 和 clac.exe 都在您的上下文中运行。那么,如果您打开 Internet Explorer 并自己访问该网站会发生什么? Wkhtmltopdf.exe 会给出什么样的错误?
标签: c# pdf active-directory windows-authentication wkhtmltopdf