如何在Blazor客户端的JS文件下载函数中传入Bearer授权Token?
Blazor客户端授权API文件下载:Bearer Token传递方案
核心问题原因
直接通过浏览器URL跳转下载时,浏览器不会自动携带Bearer Token到请求头里,这就是加了[Authorize]后返回401的根本原因。下面是三种可行的解决方案,按推荐优先级排序:
方案一:通过HttpClient获取流后触发下载(推荐)
利用Blazor内置的HttpClient(已集成Token管理)先从API拉取文件流,再通过JS将流转为Blob触发下载,既安全又避免了URL跳转的Token传递问题。
前端代码(Blazor组件)
@inject HttpClient Http @inject IJSRuntime JSRuntime <button @onclick="DownloadAuthorizedFile">下载授权文件</button> @code { private async Task DownloadAuthorizedFile() { // 调用授权API,HttpClient会自动携带Bearer Token var response = await Http.GetAsync("api/files/export", HttpCompletionOption.ResponseHeadersRead); response.EnsureSuccessStatusCode(); // 从响应头提取文件名(API需在Content-Disposition中返回) var fileName = response.Content.Headers.ContentDisposition?.FileNameStar ?? response.Content.Headers.ContentDisposition?.FileName ?? "exported-file"; fileName = fileName.Trim('"'); // 去掉可能存在的引号 // 获取文件流并调用JS触发下载 using var streamRef = new DotNetStreamReference(await response.Content.ReadAsStreamAsync()); await JSRuntime.InvokeVoidAsync("downloadFromStream", fileName, streamRef); } }
配套JS代码(放在wwwroot/js/utils.js或index.html中)
window.downloadFromStream = async (fileName, streamRef) => { const stream = await streamRef.stream(); const blob = new Blob([stream]); const downloadUrl = URL.createObjectURL(blob); const anchor = document.createElement('a'); anchor.href = downloadUrl; anchor.download = fileName; anchor.click(); URL.revokeObjectURL(downloadUrl); anchor.remove(); };
方案二:Token作为查询参数传递(仅适合非敏感场景)
如果必须用URL跳转方式(比如超大文件不想占用客户端内存),可以将Token编码后放在查询参数里,但注意查询参数可能被日志记录,仅适合非敏感文件且必须在HTTPS环境下使用。
前端代码
@inject IJSRuntime JSRuntime @inject IAccessTokenProvider TokenProvider private async Task TriggerDownloadWithQueryToken() { var tokenResult = await TokenProvider.RequestAccessToken(); if (tokenResult.TryGetToken(out var token)) { // 对Token进行URL编码,避免特殊字符问题 var encodedToken = Uri.EscapeDataString(token.Value); var downloadUrl = $"api/files/export?authToken={encodedToken}"; await JSRuntime.InvokeVoidAsync("triggerFileDownload", downloadUrl); } }
API端修改(读取查询参数验证Token)
[Authorize] [HttpGet("export")] public IActionResult ExportFile([FromQuery] string authToken) { // 手动验证Token逻辑(可复用原有JWT验证逻辑) var validationResult = _jwtValidator.ValidateToken(authToken); if (!validationResult.IsValid) { return Unauthorized(); } // 返回文件逻辑 var fileBytes = System.IO.File.ReadAllBytes("path/to/target/file"); return File(fileBytes, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "data.xlsx"); }
方案三:Cookie传递Token(需同域配置)
如果你的Blazor客户端和API处于同域(或子域),可以将Token写入Cookie,让浏览器自动携带。之前失败大概率是Cookie配置问题,以下是正确配置方式:
Blazor客户端登录后设置Cookie
@inject IJSRuntime JSRuntime private async Task PersistTokenToCookie(string token) { // 设置Secure、SameSite=Strict确保安全,maxAge按实际过期时间设置 await JSRuntime.InvokeVoidAsync("setAuthCookie", "BearerToken", token, "/", 3600); }
配套JS代码
window.setAuthCookie = (name, value, path, maxAge) => { document.cookie = `${name}=${value}; path=${path}; max-age=${maxAge}; secure; same-site=strict`; };
API端配置(从Cookie读取Token)
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { // 原有JWT验证参数(Issuer、Audience、SigningKey等) }; // 添加从Cookie读取Token的逻辑 options.Events = new JwtBearerEvents { OnMessageReceived = context => { var token = context.Request.Cookies["BearerToken"]; if (!string.IsNullOrEmpty(token)) { context.Token = token; } return Task.CompletedTask; } }; });
内容的提问来源于stack exchange,提问作者anhtv13
相关产品推荐
相关产品推荐

