【问题标题】:.NET Web API 2 OWIN Bearer Token Authentication direct call.NET Web API 2 OWIN Bearer Token Authentication 直接调用
【发布时间】:2016-10-14 03:49:27
【问题描述】:

我的 Web Api 项目有问题。 我有文件存储在我的数据库中,并想在新窗口中直接调用它们以查看/保存(URL 像:/api/Files/5 - 5 beeing the FileId)

对于我的一般 AJAX 请求,我使用 Bearer Token 进行了所有工作,使用 AngularJS 处理普通数据,它就像一个魅力。对于该文件,我创建了一个控制器,该控制器在浏览器中显示具有相应 MIME 类型的文件。但是现在我将操作更改为 [Authorize] 我得到了一个 Access Denied 这是正确的,因为我没有在 HTTP-Header 中传递 access_token。

如果可以通过查询字符串传递令牌,我做了很多研究,但没有发现任何帮助。

现在我的计划是从我的控制器中删除 [Authorize] 属性并尝试自己验证令牌,但我不知道如何。

有人知道我怎样才能让它工作吗?

【问题讨论】:

    标签: validation asp.net-web-api


    【解决方案1】:

    我在我的应用程序(AngularJS,WebAPI 2)中实现了不记名令牌身份验证,我遇到了类似的问题 - 我需要通过单击链接来允许下载文件。当您单击链接标题时不会发送。 :( 因此,我在查询字符串中发送了令牌值以下载文件

    .../mywebapp/api/files/getfile/3?access_token=jaCOTrGsaak6Sk0CpPc1...

    并将“授权”标头设置为 Startup.Auth.cs 中的令牌值。代码如下:

    public void ConfigureAuth(IAppBuilder app)
    {
        //It needs for file downloads
        app.Use(async (context, next) =>
        {
            if (context.Request.QueryString.HasValue)
            {
                if (string.IsNullOrWhiteSpace(context.Request.Headers.Get("Authorization")))
                {
                    var queryString = HttpUtility.ParseQueryString(context.Request.QueryString.Value);
                    string token = queryString.Get("access_token");
    
                    if (!string.IsNullOrWhiteSpace(token))
                    {
                        context.Request.Headers.Add("Authorization", new[] { string.Format("Bearer {0}", token) });
                    }
                }
            }
    
            await next.Invoke();
        });
        // Enable the application to use bearer tokens to authenticate users
        app.UseOAuthBearerTokens(OAuthOptions);
    }
    

    【讨论】:

    • 这对我有用,是我尝试过的几个选项中最简单的一个。也就是说,还有其他方法可能是最好的,所以在您自己检查替代方法之前不要使用它。
    • 我希望我能多次投票。智能、简洁、优雅……等等 :)
    • @johnwest 请与我们分享替代方法
    • 非常感谢。这是文件下载的完美解决方案。我尝试使用 POST 方法下载文件,并在标头中应用熊令牌,但无法使用 post 方法下载文件。这对我来说是安全且完美的解决方案。
    【解决方案2】:
    【解决方案3】:

    对于 ASP .Net Core,我根据 Forward 的回答做了类似的事情

    扩展方法

      public static void UseQueryStringBearerValidation(this IApplicationBuilder app)
        {
            //It needs for file downloads
            app.Use(async (context, next) =>
            {
                if (context.Request.QueryString.HasValue)
                {
                    if (string.IsNullOrWhiteSpace(context.Request.Headers["Authorization"].ToString()))
                    {
                        var queryString = QueryHelpers.ParseQuery(context.Request.QueryString.Value);
                        var token = queryString["access_token"].ToString();
    
                        if (!string.IsNullOrWhiteSpace(token))
                        {
                            context.Request.Headers.Add("Authorization", new[] {$"Bearer {token}"});
                        }
                    }
                }
    
                await next();
            });
        }
    

    用法

    StartUp.cs -> Configure() 方法

                app.UseCustomExceptionHandler();
                app.UseQueryStringBearerValidation(); // <-- add before Jwt Handler
                app.UseCustomJwtBearerValidation();
                app.AddHttpContextProperties();
                app.UseStaticFiles();
                app.UseMvc(MiddlewareAppConfiguration.AddRouteMappings);
    

    【讨论】:

      【解决方案4】:

      虽然我不确定这是一个好主意,但您可以实现 DelegatingHandler 来实现您想要的。

      public class QueryStringBearerToken : DelegatingHandler
      {
          protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
          {
              var bearerToken = request.GetQueryNameValuePairs()
                                       .Where(kvp => kvp.Key == "bearerToken")
                                       .Select(kvp => kvp.Value)
                                       .FirstOrDefault();
      
              if(!String.IsNullOrEmpty(bearerToken))
              {
                  request.Headers.Add("Authorization", "Bearer " + bearerToken);
              }
              return base.SendAsync(request, cancellationToken);
          }
      }
      

      此处理程序将查找名为"bearerToken" 的查询字符串,如果存在,会将其添加到请求标头中,以供后续处理程序/过滤器处理。您可能需要先检查标头是否已经存在并且在这种情况下不覆盖。您可以按照通常的方式在配置阶段添加此处理程序:

      config.MessageHandlers.Insert(0, new QueryStringBearerToken ());
      

      对/YourRoute?bearerToken=theToken的请求会传入DelegatingHandler,将查询字符串中传入的token添加到原始请求的header列表中,常规的Bearer Token认证会查找header并找到它。

      【讨论】:

      • 感谢您的回复。它有点工作,但它没有。调试器命中代码并且令牌被正确读取,但我仍然收到我未授权的错误消息。如果我尝试对令牌进行硬编码,对于实际上具有授权属性的请求,我会收到重复错误...我的猜测是该处理程序在验证后启动?
      • @Marvin 预期会出现重复错误。正如我所说,我没有把逻辑来处理请求中已经有 Authorization 标头的情况。将委托处理程序首先放在管道中 (Insert(0, ...)) 应该在授权开始之前执行它。
      • 另一点要注意的是,如果在查询字符串中传递令牌的编码。由于= 可以是令牌的一部分,它可能会截断GetQueryNameValuePairs() 的值。您应该在放置断点时检查您在查询字符串中传递的令牌是否与bearerToken 变量相同。如果是这种情况,它将解释 401,因为不记名令牌无法识别。
      • 刚刚检查过了。我从调试器中的变量中复制了令牌并将其粘贴到带有授权的提琴手中,我得到了 200。所以令牌被正确读取。
      猜你喜欢
      • 2015-12-25
      • 2023-03-15
      • 2016-10-10
      • 2021-02-06
      • 2022-10-31
      • 2014-10-05
      • 2013-11-25
      • 2018-04-20
      • 1970-01-01
      相关资源
      最近更新 更多