我正在尝试从需要身份验证的页面打印 PDF 发票 (
https://localhost:44362/invoice
)。当授权关闭时,所有这些都可以正常工作,但是当我打开它时,整个事情就崩溃了。我正在使用带有身份验证功能的.NET Core 2.1 MVC。我尝试了两种不同的解决方案,但都以不同的方式失败。
尝试1:
渲染可以了,但是登录失败,生成的pdf是登录页面。据我所知,这是身份验证失败时的正常行为。
var uri = new Uri("https://localhost:44362/invoice");
var newPdf = new HtmlToPdf()
{
PrintOptions = new PdfPrintOptions()
{
//..omitted for brevity
},
LoginCredentials = new HttpLoginCredentials()
{
EnableCookies = true,
LoginFormPostVariables = new Dictionary<string, string>()
{
{ "Email", "[email protected]" },
{ "Password", "secretysecret" }
},
LoginFormUrl = new Uri("https://localhost:44362/login")
}
};
var result = newPdf.RenderUrlAsPdf(uri);
尝试2:
我从原始请求中获取授权 cookie。这是有效的,至少到目前为止我可以实际获取 cookie 并将其设置为
LoginCredentials.CustomCookies
。我将其与浏览器请求进行了比较,cookie 似乎是正确的。该集合 Request.Cookies
包含两块 cookie,一块用于防伪,另一块用于身份。newPdf.RenderUrlAsPdf(uri)
返回 null
,我不明白为什么。原因一定是 CustomCookies
中设置的 LoginCredentials
以某种方式失败,但堆栈跟踪没有提供有关失败原因的任何信息。需要明确的是,即使未使用授权,此方法也会失败。
var uri = new Uri("https://localhost:44362/invoice");
var cookies = Request.Cookies;
Dictionary<string, string> customCookies = cookies.ToDictionary(c => c.Key, c => c.Value);
var newPdf = new HtmlToPdf()
{
PrintOptions = new PdfPrintOptions()
{
//..omitted for brevity
},
LoginCredentials = new HttpLoginCredentials()
{
EnableCookies = true,
CustomCookies = customCookies
//LoginFormPostVariables = new Dictionary<string, string>()
//{
// { "Email", "[email protected]" },
// { "Password", "secretysecret" }
//},
//LoginFormUrl = new Uri("https://localhost:44362/login")
}
};
var result = newPdf.RenderUrlAsPdf(uri);
因为这是搜索 IronPDF 身份验证/cookie 问题时出现的唯一真实搜索结果,所以我想添加一些信息,这些信息花费了我比我愿意承认的更长的时间来弄清楚......
这种利用自定义 cookies 功能并使用 render url 方法的方法实际上确实有效。它将使用复制的身份验证 cookie 并成功进行身份验证以获取标记和任何链接的资源。请注意,您将需要使用较新的静态方法,因为此处显示的旧实例方法是遗留/已弃用的。
我正在用头撞墙,假设渲染html方法IronPdf.ChromePdfRenderer.StaticRenderHtmlAsPdfAsync的工作方式就像渲染url方法IronPdf.ChromePdfRenderer.StaticRenderUrlAsPdfAsync一样。遗憾的是,render html 方法根本无法以这种方式工作。您可以根据需要设置自定义 cookie,但任何对链接资源的请求都不会使用它们。
这在 Azure Web App 环境中尤其重要,您在其中利用身份提供程序并需要对整个站点进行身份验证。这种复制 AppServiceAuthSession cookie 并在 IronPDF 的 Url 方法调用上使用它的方法被视为已通过身份验证。
不幸的是,IronPDF doc 倾向于引导您使用 html 方法,因为在需要呈现受身份验证保护的内容时更可靠。在他们的辩护中,custom cookie doc确实明确声明它旨在与url方法一起使用 - 当你想到它时这是有道理的 - 我只是不断浏览那个小金块,显然支持人员也不知道.
我仍然更喜欢自己将视图渲染为 html 字符串,并使用 html 方法,这样我将看看支持人员可以告诉我什么。至少现在我除了开放链接资源以进行匿名访问之外还有一个选择。
编辑: 另一个需要注意的小细节是关于 HtmlHeader/HtmlFooter 属性的使用。我(愚蠢地)假设我在那里添加的任何标记都可以轻松地通过样式表进行样式设置,而不必进行硬编码。如果您不必担心身份验证,那么可能可以,但祝您好运。页眉和页脚实际上被视为单独的 html 文档,因此如果您希望将应用于它们的样式应用于您的主文档内容,则有一个属性 - LoadStylesAndCSSFromMainHtmlDocument。遗憾的是,这个属性明确指出它仅适用于 html 方法,不适用于 url 方法。因为前面提到的 auth/cookie 问题,我不得不使用 url 方法,所以我再次不走运。然后我找到了 CustomCssUrl 属性,says 它用于在渲染之前将指定的样式表应用到 html。但尝试之后,我很快意识到对此样式表的调用显然不使用自定义 cookie,因此现在我们又因为身份验证而无法提取样式表。最终,我只是硬编码了传递给 HtmlHeader/HtmlFooter 的标记中的样式,因为此时我开始质疑我的生活选择 - 哈哈。
为了帮助任何偶然发现此线程的人,这里有一个工作示例(控制器上的方法):
ChromePdfRenderer renderer = new ChromePdfRenderer();
renderer.RenderingOptions.CustomCookies = Request.cookiesAsDictionary();
renderer.RenderingOptions.WaitFor.JavaScript();
// Render from URL
String path = Url.Action(action, routeValues);
String url = UriHelper.BuildAbsolute(Request.Scheme, Request.Host, Request.PathBase);
url = Flurl.Url.Combine(url, path);
PdfDocument pdf = await renderer.RenderUrlAsPdfAsync(url);
Response.Headers.Append("Content-Disposition", "inline");
// Output PDF document
fileName = fileName ?? $"{GetType().Name}.pdf";
return File(pdf.BinaryData, "application/pdf", fileName);
然后添加一个扩展方法,用于从当前请求中提取 cookie:
public static Dictionary<String, String> cookiesAsDictionary(this HttpRequest request)
{
Dictionary<string, string> result = new Dictionary<string, string>();
foreach (var key in request.Cookies.Keys)
{
result.Add(key, request.Cookies[key]);
}
return result;
}