C# 在http请求中向Web API.net Core 2发送未经授权的JWT时中止连接

C# 在http请求中向Web API.net Core 2发送未经授权的JWT时中止连接,c#,asp.net-web-api,file-upload,asp.net-core,jwt,C#,Asp.net Web Api,File Upload,Asp.net Core,Jwt,我正在编写一个.NETCore2.0WebAPI控制器,它使用一个多部分类型的http请求执行文件上传,并基于所描述的流技术 在这一点上,我必须说,如果你愿意,我可以跳过下面两段,这两段描述了导致我需要解决问题的原因,这两段后面描述了这个问题 我最初考虑通过在multipart请求的第一部分中发送身份验证数据来验证用户,并在读取用户数据后立即验证用户,方法是联系数据库并执行正确的请求。但是,我认为,由于这是一个流请求,因此使用数据库对用户进行身份验证的任何延迟都会延迟读取带有文件的流。这将导致T

我正在编写一个.NETCore2.0WebAPI控制器,它使用一个多部分类型的http请求执行文件上传,并基于所描述的流技术

在这一点上,我必须说,如果你愿意,我可以跳过下面两段,这两段描述了导致我需要解决问题的原因,这两段后面描述了这个问题

我最初考虑通过在multipart请求的第一部分中发送身份验证数据来验证用户,并在读取用户数据后立即验证用户,方法是联系数据库并执行正确的请求。但是,我认为,由于这是一个流请求,因此使用数据库对用户进行身份验证的任何延迟都会延迟读取带有文件的流。这将导致TCP接收缓冲区充满数据(可能也会增加其大小),并会破坏流式传输文件(而不是缓冲)的目的,因为此连接的内存消耗将增加

为了解决这个问题,我考虑使用两步身份验证。WebAPI用户将首先执行请求并请求JWT。然后它会在上传请求中使用这个JWT。据我所知,JWT身份验证应该比数据库请求快得多,因为它是通过使用存储在服务器中的密钥验证JWT来执行的,所以前面的问题不应该存在

我实现了上传请求的JWT身份验证,遵循了来自的这一非常好的描述,它工作得很好。更具体地说,控制器具有一个
[Authorize]
属性,该属性通过在执行控制器之前验证JWT,强制Web API对用户进行身份验证

我面临的问题是,使用上述建议的解决方案,当未经授权的用户尝试上载文件时,控制器操作永远不会被调用。身份验证引擎向用户返回未加密(401)响应,并允许用户继续发送文件数据。最后一部分是我的问题。我希望未经授权的用户(可能是攻击者)接收401响应,然后终止连接

因此,我想要的是保持身份验证/授权部分的工作状态,并在发送401响应后终止用户连接。我知道(并且已经测试过)从控制器操作方法内部可以通过调用来终止http连接

HttpContext.Abort();

我怀疑通过使用过滤器,我可以做我想做的事情,但我对过滤器不是很熟悉,因此我提出了这个问题。

我们可以通过使用
IAuthorizationFilter

在它里面,我们将设置一个特殊的
ActionResult
名为
abortAuthorizedConnectionResult
,在其中,我们将状态代码设置为
401
,内容长度设置为
0
,并通过调用
Response.Body.Flush()
确保在调用
Abort()
之前将其发送到客户端

这里有一个名为abortAuthorizedConnections的授权筛选器:

class AbortUnauthorizedConnections : Attribute, IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationFilterContext context)
    {
        if (context.HttpContext.User?.Identity == null || !context.HttpContext.User.Identity.IsAuthenticated)
        {
            // by setting this we make sure the pipe-line will get short-circuited.
            context.Result = new AbortUnauthorizedConnectionResult();
        }
    }
}
因为我们继承了
属性
,我们可以在上传操作中使用它,如下所示:

[Authorize]
[AbortUnauthorizedConnections]
public async Task<IActionResult> UploadFile()
{
    // we do whatever we want.
}

现在,如果未经授权的用户尝试访问此控制器,将获得401,其连接将中止。

这是我实际实施的解决方案,因为它很简单,遵循@Tratcher的建议:

首先,我从控制器操作方法中删除了
[Authorize]
属性。然后,我编写了控制器操作方法的开头,如下所示:

    public async Task<string> UploadFile()
    {
        if (!(await HttpContext.AuthenticateAsync()).Succeeded)
        {
            HttpContext.Response.StatusCode = 401; //Unauthorized
            HttpContext.Response.Headers.Add("Content-Length", "0");
            HttpContext.Response.Body.Flush();
            HttpContext.Abort();
            return null;
        }

        ...
    }
public异步任务上传文件()
{
如果(!(等待HttpContext.authenticateSync()).successed)
{
HttpContext.Response.StatusCode=401;//未经授权
HttpContext.Response.Headers.Add(“内容长度”,“0”);
HttpContext.Response.Body.Flush();
HttpContext.Abort();
返回null;
}
...
}

您还可以删除authorize属性,并在操作中明确指定do。调用HttpContext.authenticateSync获取用户。如果成功,则继续,否则发送一个401,连接:close,内容长度:0。在响应主体上调用flush使其发送,然后调用Abort。谢谢。我采纳了你的建议,效果很好!实际上我做了
if(!(wait HttpContext.authenticatesync()).succeed)
,在if块中,我形成了响应并中止了连接,就像@Ashkan在过滤器中所做的那样。@Tratcher,我想你也应该写下你的答案,它非常简单而且有效。我将投票表决。请继续,并张贴您的工作代码作为答案。谢谢您的回答。在未经授权的访问情况下,您的解决方案确实会中止连接,但之后仍会调用控制器操作方法(在您的示例中为“UploadFile()”)。有办法避免吗?@retset,np。编辑了答案以防止出现一些异常和您所说的问题。非常感谢,我测试了它,现在它工作得非常好!Response.ContentLength。
    public async Task<string> UploadFile()
    {
        if (!(await HttpContext.AuthenticateAsync()).Succeeded)
        {
            HttpContext.Response.StatusCode = 401; //Unauthorized
            HttpContext.Response.Headers.Add("Content-Length", "0");
            HttpContext.Response.Body.Flush();
            HttpContext.Abort();
            return null;
        }

        ...
    }