如何在启用JWT Token授权的.NET Core WebApi项目中下载文件

背景

前几天,做项目的时候遇到一个文件下载的问题。当前系统是一个前后端分离的项目,前端是一个AngularJs项目, 后端是一个.NET Core WebApi项目。后端的Api项目使用了Jwt Token授权,所以每个Api请求都需要传递一个Bearer Token。

这一切都看起来理所当然,但是当需要从WebApi下载文件的时候,出现了问题。以前下载文件的时候,我们可以在Javascript中使用window.open(‘[文件下载Api]‘)的方式下载文件,但是这个方法不能接收Bearer Token, 所以就会导致文件下载失败,返回一个401未授权的响应码。

可能有的同学会将这个文件下载Api设置成允许匿名访问,但是这样会导致系统不安全。

那么有什么好一点的方式可以解决这个问题呢?

解决方案

使用Blob对象

Blob对象可以看做是Javascript中的二进制容器, 它可以存储文件的二进制流。所以我们可以通过如下思路完成文件下载:

  1. 创建一个异步请求来下载文件的二进制流,这个请求的头部需要附加Bearer Token,在方法回调中,我们将文件二进制流保存在一个Blob对象中
  2. 我们使用Javascript添加一个虚拟的超链接,超链接的href属性指向了刚刚的Blob对象。
  3. 我们通过模拟点击这个虚拟的超链接,来完成文件下载的功能。
let anchor = document.createElement("a");
let file = 'https://www.example.com/api/getFiles/'+fileId;

let headers = new Headers();
headers.append('Authorization', 'Bearer MY-TOKEN');

fetch(file, { headers })
    .then(response => response.blob())
    .then(blobby => {
        let objectUrl = window.URL.createObjectURL(blobby);

        anchor.href = objectUrl;
        anchor.download = 'some-file.pdf';
        anchor.click();

        window.URL.revokeObjectURL(objectUrl);
    });

这个方案有两个缺点:

  1. 就是只有当文件流完全读取到Blob对象中之后,才会触发真正的文件下载。因此如果文件内容过大话,浏览器会有一个长时间的静止,当文件流全部加载到Blob对象之后,才会触发下载操作。所以这里可能需要添加自己添加一个Loading效果,给用户一些提示。
  2. 并不是所有的浏览器都支持Blob对象,在一些老的浏览器中Blob对象是不被支持的。

使用ASP.NET Core中的Data Protection

在之前的博客中,我有讲解过ASP.NET Core中的Data Protection功能, 我们可以使用Data Protection将一些敏感信息加密。所以这里我们可以将一个需要授权才能使用下载文件的Api, 替换成2个Api

  • 第一个Api是需要授权的,它主要负责查看文件ID是否存在,如果存在,就使用Data Protection, 将这个ID加密,并返回给前端,这个ID的加密时效设置为5秒。
  • 第二个Api是不需要授权的,允许匿名访问。它接收前一个Api提供的加密ID, 如果ID可以解密成功,就返回这个ID对应的文件流。

第一个Api的实例代码:

[HttpGet]
[Route("~/api/file_links/{fileId}")]
public IActionResult GetFileLink(Guid fileId)
{
    if (_files.Any(p => p.FileId == fileId))
    {
        var matchedFile = _files.First(p => p.FileId == fileId);

        return Content(this.protector.Protect(matchedFile.FileId.ToString(),
            TimeSpan.FromSeconds(5)));
    }

    return StatusCode(500);
}

第二个Api的实例代码:

[HttpGet]
[AllowAnonymous]
[Route("~/api/raw_files/{id}")]
public IActionResult GetRawFile(string id)
{
    try
    {
        var rawId = Guid.Parse(this.protector.Unprotect(id));
        var matchedFile = _files.First(p => p.FileId == rawId);
        matchedFile.FileContent.Position = 0;

        return File(matchedFile.FileContent, "text/plain", "helloWorld.txt");
    }
    catch
    {
        return StatusCode(401);
    }
}

使用这种方式,虽然我们开放了一个未经授权就可以访问的Api入口,但是由于使用了Data Protection, 所以对于非法的请求,系统也可以进行一定的屏蔽。

最终效果

针对以上2种下载方式,我创建了一个小项目,项目地址:https://github.com/lamondlu/Sample_DownloadFileInAuth, 打开之后页面如下。

普通下载

由于缺少Token, 所以下载失败,返回401

使用Blob下载

使用Blob下载之后,文件下载成功

使用Data Protection

使用Data Protection后,文件下载成功

总结

本文只算抛砖引玉,如果大家有更好的解决方案,欢迎一起讨论。

原文地址:https://www.cnblogs.com/lwqlun/p/10204918.html

时间: 2024-10-29 19:59:33

如何在启用JWT Token授权的.NET Core WebApi项目中下载文件的相关文章

[转]三分钟学会.NET Core Jwt 策略授权认证

[转]三分钟学会.NET Core Jwt 策略授权认证 一.前言# 大家好我又回来了,前几天讲过一个关于Jwt的身份验证最简单的案例,但是功能还是不够强大,不适用于真正的项目,是的,在真正面对复杂而又苛刻的客户中,我们会不知所措,就现在需要将认证授权这一块也变的复杂而又实用起来,那在专业术语中就叫做自定义策略的API认证,本次案例运行在.NET Core 3.0中,最后我们将在swagger中进行浏览,来尝试项目是否正常,对于.NET Core 2.x 版本,这篇文章有些代码不适用,但我会在文

从壹开始前后端 [vue后台] 之二 || 完美实现 JWT 滑动授权刷新

缘起 哈喽大家周一好!不知道小伙伴们有没有学习呀,近来发现各种俱乐部搞起来了,啥时候群里小伙伴也搞一次分享会吧,好歹也是半千了(时间真快,还记得5个月前只有20多人),之前在上个公司,虽然也参与组织过几次活动,这个再说吧,毕竟都是五湖四海的小伙伴,不太好聚??.今天要说的内容很简单,但是个人感觉很实用,从文章标题就可见一斑:JWT的滑动授权,这个问题我被问了不下 n 次,从 6 个月前开始第一次写 JWT 授权,就有小伙伴陆陆续续在群里提问,说如何然这种无序化的 Token 令牌(不像 Sess

JWT实现授权认证

目录 一. JWT是什么 二. JWT标准规范 三. 核心代码简析 四. 登录授权示例 五. JWT 使用方式 六. JWT注意事项 一. JWT是什么 JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案.简单说,OAuth 就是一种授权机制.数据的所有者告诉系统,同意授权第三方应用进入系统,获取这些数据.系统从而产生一个短期的进入令(token),用来代替密码,供第三方应用使用.. 传统的授权认证方式,需要持久化session数据,写入数据库或文件持久层等,且授权校验依赖

android 中使用jwt token(json web token)--java

http://blog.csdn.net/mingzhnglei/article/details/51119836 下面贴上自己项目中的一个小小的example import com.nimbusds.jose.JOSEException; import com.nimbusds.jose.JWSAlgorithm; import com.nimbusds.jose.JWSHeader; import com.nimbusds.jose.JWSObject; import com.nimbusd

IdentityServer4实战 - 谈谈 JWT Token 的安全策略

一.前言 众所周知,IdentityServer4 默认支持两种类型的 Token,一种是 Reference Token,一种是 JWT Token .前者的特点是 Token 的有效与否是由 Token 颁发服务集中化控制的,颁发的时候会持久化 Token,然后每次验证都需要将 Token 传递到颁发服务进行验证,是一种中心化的比较传统的验证方式.JWT Token 的特点与前者相反,每个资源服务不需要每次都要都去颁发服务进行验证 Token 的有效性验证,该 Token 由三部分组成,其中

PHP JWT token实现

原文链接:https://www.jb51.net/article/146790.htm 机制: 代码如下: <?php /**  * PHP实现jwt  */ class Jwt {   //头部   private static $header=array(     'alg'=>'HS256', //生成signature的算法     'typ'=>'JWT'  //类型   );   //使用HMAC生成信息摘要时所使用的密钥   private static $key='12

NET Core 1.1中使用Jwt

NET Core里Jwt的生成倒是不麻烦,就是要踩完坑才知道正确的生成姿势-- Jwt的结构 jwt的结构是{Header}.{Playload}.{Signature}三截.其中Header和Playload是base64编码字符串,Signature是签名字符串. Header是比较固定的 typ是固定的"JWT". alg是你使用的签名算法,通常有HS256和RS256两种. 例子: { "alg": "RS256", "typ&

Jwt在javaweb项目中的应用核心步骤解读

1.引入jwt依赖 <!--引入JWT依赖,由于是基于Java,所以需要的是java-jwt--> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency> <dependency> <groupId>

aspnet core 2.1中使用jwt从原理到精通一

目录 原理: 根据原理使用C#语言,生成jwt: 自定义验证jwt: 使用aspnetcore 中自带的类生成jwt: 学有所得 了解jwt原理; 使用C#轻松实现jwt生成和验证 原理 jwt对所有语言都是通用的,只要知道秘钥,另一一种语言有可以对jwt的有效性进行判断; jwt的组成:Header部分Base64转化.Payload部分Base64转化.使用HS256方式根据秘钥对前面两部分进行加密后再Base64转化,其中使用的hs256加密是header部分指定的,也可以通过官网的查看,