【问题标题】:ASP.NET Core Web API Authentication allowing unauthorized accessASP.NET Core Web API 身份验证允许未经授权的访问
【发布时间】:2019-11-20 17:26:12
【问题描述】:

我正在为我的 ASP.NET Core API 创建一个身份验证方案。

它调用我的处理程序并很好地命中断点,但即使授权失败,API 调用仍会返回结果。

protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
    if (!Request.Headers.ContainsKey(AuthorizationHeaderName))
    {
        //Authorization header not in request
        return AuthenticateResult.Fail("Missing Authorization header");
    }

以我的幼稚理解,如果身份验证失败,它不应该返回数据。

我错过了什么?

详情

我在 Startup.ConfigureServices 中注册这样的方案

services.AddAuthentication(options => {
    // This (options.Default..Scheme) causes the default authentication scheme to be set.
    // Without this, the Authorization header is not checked and
    // you'll get no results. 
   options.DefaultAuthenticateScheme = BasicAuthenticationDefaults.AuthenticationScheme;
}).AddScheme<BasicAuthenticationOptions, BasicAuthenticationHandler>("Basic", null);

Startup.Config 调用

 app.UseAuthentication();
 app.UseHttpsRedirection();
 app.UseMvc();

其余代码如下所示:

using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Text;
using System.Text.Encodings.Web;
using System.Threading.Tasks;

namespace WebAPI.Authentication
{
    public interface IBasicAuthenticationService
    {
        Task<AuthenticateResult> HandleAuthenticateAsync();
    }

    public static class BasicAuthenticationDefaults
    {
        public const string AuthenticationScheme = "Basic";
    }

    public class BasicAuthenticationOptions : AuthenticationSchemeOptions
    { }

    public class BasicAuthenticationHandler : AuthenticationHandler<BasicAuthenticationOptions>
    {
        private const string AuthorizationHeaderName = "Authorization";
        private const string BasicSchemeName = "Basic";

        public BasicAuthenticationHandler(
            IOptionsMonitor<BasicAuthenticationOptions> options,
            ILoggerFactory logger,
            UrlEncoder encoder,
            ISystemClock clock)
            : base(options, logger, encoder, clock)
        {
        }

        protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
        {
            if (!Request.Headers.ContainsKey(AuthorizationHeaderName))
            {  // Rejected here. Should fail.
                //Authorization header not in request
                return AuthenticateResult.Fail("Missing Authorization header");
            }

            if ....  // never gets this far
            }

            return AuthenticateResult.Success(ticket);
        }
    }
}

这是不正确返回结果的控制器。

using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;

namespace TMAWebAPI.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class ValuesController : ControllerBase
    {
        // GET api/values
        [HttpGet]
        public ActionResult<IEnumerable<string>> Get()
        {
            return new string[] { "value1", "value2" };
        }
    } 
}

所有这些代码行都在调试器中被命中,因此该部分似乎工作正常。

但即使身份验证失败,API 调用仍会返回结果。

更新:
向 Controller 添加 AuthenticationScheme 属性会使其失败。
像这样:

[Route("api/[controller]")]
[ApiController]
[Authorize(AuthenticationSchemes = "Basic")]
public class ValuesController : ControllerBase

这不好。默认情况下它应该会失败,而不是必须将它添加到每个控制器。

更新 2:

向 services.AddMvc 添加过滤器看起来很有希望,但这也不起作用。文档声称您不必实施授权过滤器,因为它们已包含在内。不是我能找到的。

我继承了 AuthorizeAttribute,使用了 Matti Price 的想法,以及 AddMvc 所需的 IFilterMetadata。编译但仍然允许未经授权的访问。

public class BasicAuthorizeAttribute : AuthorizeAttribute, IFilterMetadata { }       

services.AddMvc(options => {
    options.Filters.Add(typeof(BasicAuthorizeAttribute));
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

更新 3:
试过了

policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser()

按照 Matti 的建议,但返回了

InvalidOperationException: No authenticationScheme was specified, and there was no DefaultChallengeScheme found.

我对重定向到不存在的 API 登录页面没有任何兴趣,所以我尝试了

policy = new AuthorizationPolicyBuilder().AddAuthenticationSchemes(new[] {BasicAuthenticationDefaults.AuthenticationScheme })

编译但抛出异常

InvalidOperationException Message=AuthorizationPolicy must have at least one requirement.

【问题讨论】:

  • 除非我弄错了,否则您已经添加了身份验证服务 (services.AddAuthentication(...),但您是否还需要将应用程序配置为 app.UseAuthentication()?可能值得用其余部分更新您的代码配置。
  • @BrendanGreen 是的。我错过了。更新。依然没有。我想我会添加那些缺失的部分。我希望避免这种情况。
  • 向 Controller 添加 AuthenticationScheme 属性会使其失败。这不好。默认情况下它应该会失败。

标签: c# authentication asp.net-web-api asp.net-core-2.0 access-token


【解决方案1】:

您需要将[Authorize] 属性添加到您的控制器,以使授权对其结果进行实际操作。您可以像这样全局添加它:

services.AddMvc(config =>
{
    var policy = new AuthorizationPolicyBuilder()
                 .RequireAuthenticatedUser()
                 .Build();
    config.Filters.Add(new AuthorizeFilter(policy));
});

【讨论】:

  • 这看起来很有希望,但它会抛出“消息=类型 'Microsoft.AspNetCore.Authorization.AuthorizeAttribute' 必须派生自 'Microsoft.AspNetCore.Mvc.Filters.IFilterMetadata'。”我添加了“使用 Microsoft.AspNetCore.Authorization;”会不会是错的?
  • 我实现了这个,见上文,但它不起作用。
  • @BWhite 哎呀,我想我给了你一个旧的 .netcore 版本的方法。试试那个更新的。
  • 没有。 InvalidOperationException:未指定 authenticationScheme,也未找到 DefaultChallengeScheme。感谢您的尝试。
  • RequireAuthenticatedUser 感觉不对,因为没有 AuthenticatedUser 使用 API。我只是希望它需要 AuthenticationHandler。
【解决方案2】:

最终解决方案使用 AddMVC。解决方案是,除了添加方案外,方案还需要一个需求。

这是可行的。如果我不发送任何 auth 标头,它会返回一个空页面。如果我发送一个过期的标头,那么它会发送 500。应该是 401。但它不返回任何值,这就是我真正关心的。

public class TokenAuthorizationRequirement: IAuthorizationRequirement {}

services.AddMvc(config => {
   var policy = new AuthorizationPolicyBuilder()
      .AddAuthenticationSchemes(new[] {BasicAuthenticationDefaults.AuthenticationScheme })
      .AddRequirements(new BasicAuthorizationRequirement())
      .Build();
   config.Filters.Add(new AuthorizeFilter(policy));
});

【讨论】:

  • 我将@Matti-Price 的答案标记为解决方案,因为我从没想过要使用 AuthorizationPolicyBuilder 所以他必须获得荣誉。
猜你喜欢
  • 2012-05-27
  • 2017-01-23
  • 2012-09-10
  • 1970-01-01
  • 2022-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-17
相关资源
最近更新 更多