下载文件会导致用户注销



我有一个ASP.NET MVC 4.5.2网站(由于托管限制(,其中有一个带有操作链接的管理限制区域,单击时可以为用户下载.csv或.xlsx文件。

在当地,它运行得非常好。

然而,当被推出生产时,单击下载按钮会导致用户注销并显示登录屏幕,就好像他们还没有经过身份验证一样。然后,登录会导致下载真正开始(因为returnUrl被设置为下载按钮的操作链接(。

以下代码片段是我所拥有的经过修剪的版本:

管理员控制器

[Authorize(Roles = "Admin")]
public class AdminController : BaseController
{
...
[HttpGet]
public ActionResult Users()
{
var users = _context.PreSignups
.Where(x => x.IsDeleted == false)
.OrderBy(x => x.DateCreated).ToList();
CheckMessages();
return View(users);
}
[HttpGet]
public ActionResult Download_PreSignupUsersToExcel()
{
var users = _context.PreSignups
.Where(x => x.IsDeleted == false)
.OrderBy(x => x.DateCreated).ToList().ToDataTable();
DocumentService.WriteToSpreadsheet(users, $"PreSignupUsers_{DateTime.UtcNow.ToString("yyyy_MM_dd_hh_mm_ss")}.xlsx", true, Response);
// NOTE: Due to the Response being sent back in DocumentService.WriteToSpreadsheet() the below is mostly redundant as the response has already closed by this point.
TempData["Message"] = "Download started";
return RedirectToAction("Logs", "Admin");
}

DocumentService.cs

public static void WriteToSpreadsheet(DataTable dt, string filename, bool hasHeaders, HttpResponseBase response, enFileType fileType = enFileType.Xlsx)
{
... // Build the data
// Write the data
using (var exportData = new MemoryStream())
{
response.Clear();
workbook.Write(exportData);
if (fileType == enFileType.Xlsx) //xlsx file format
{
response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
response.AddHeader("Content-Disposition", $"attachment;filename={filename}");
response.BinaryWrite(exportData.ToArray());
}
else if (fileType == enFileType.Xls)  //xls file format
{
response.ContentType = "application/vnd.ms-excel";
response.AddHeader("Content-Disposition", $"attachment;filename={filename}");
response.BinaryWrite(exportData.GetBuffer());
}
response.End();
}
}

视图在某个时刻包含以下操作链接,以便对上述内容进行GET调用。单击此按钮会导致用户明显地以"admin/Download_PreSignupUsersToExcel"作为returnUrl注销到登录屏幕。

@Html.ActionLink("Export .Xlsx", "Download_PreSignupUsersToExcel", "Admin", null, new { @class="btn btn-primary" })

作为参考,BaseController继承自Controller类,并提供了一种存储ApplicationDbContext和LoggingService的方便方式,不应该对上述内容产生任何影响。

我对代码视而不见。

有什么想法吗?

好的,所以浏览器只会监听特定请求的单个响应。

我将代码的下载部分移动到它自己的AdminDownloadController API中。然后,通过移除response.End();并返回具有所有相关数据的HttpResponseMessage,并用它替换来自控制器的标准ActionResult,下载在相同的经过验证和授权的会话中启动,而不将用户注销。

需要注意的是,如果没有一些JS魔法,你就无法在客户端处理响应,比如显示消息。AJAX调用在身份验证和授权方面存在问题,因此请选择阻力最小的路径。。。除非你喜欢那种事!

以下是适用于任何需要它的人的代码摘要:

AdminDownloadController.cs

[Authorize(Roles = "Admin")]
public class AdminDownloadController : BaseApiController
{
// GET: api/AdminDownload/PreSignupUsersToExcel
public HttpResponseMessage Get(string downloadName)
{
var response = new HttpResponseMessage(HttpStatusCode.NotFound);
switch (downloadName)
{
case "PreSignupUsersToExcel":
var users1 = _context.PreSignups
.Where(x => x.IsDeleted == false)
.OrderByDescending(x => x.DateCreated).ToList().ToDataTable();
response = DocumentService.WriteToSpreadsheet(users1, $"PreSignupUsers_{DateTime.UtcNow.ToString("yyyy_MM_dd_hh_mm_ss")}.xlsx", true);
break;
...
}
return response;
}
}

DocumentService.cs

public static HttpResponseMessage WriteToSpreadsheet(DataTable dt, string filename, bool hasHeaders, enFileType fileType = enFileType.Xlsx)
{            
// Build Data
...
// StreamData
using (var exportData = new MemoryStream())
{
workbook.Write(exportData);
var response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new ByteArrayContent(exportData.ToArray());
response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = filename;
if (fileType == enFileType.Xlsx)
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
else if (fileType == enFileType.Xls)
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.ms-excel");
return response;
}
}

WhateverView.cshtml

...
@Html.ActionLink("Export .Xlsx", "AdminDownload", "Api", new { downloadName = "PreSignupUsersToExcel" }, new { @class = "btn btn-primary" })
...

最新更新