ASP.NET Core Web API 身份验证允许未经授权的访问
ASP.NET Core Web API Authentication allowing unauthorized access
我正在为我的 ASP.NET 核心 API 创建身份验证方案。
它调用我的处理程序并命中断点,但即使授权失败,API 调用仍然会产生 return 结果。
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
if (!Request.Headers.ContainsKey(AuthorizationHeaderName))
{
//Authorization header not in request
return AuthenticateResult.Fail("Missing Authorization header");
}
以我天真的理解,如果身份验证失败,它不应该 return 数据。
我错过了什么?
详情
我在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);
}
}
}
这里是不正确 returning 结果的控制器。
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 调用仍然 returning 结果,即使它未通过身份验证。
更新:
向控制器添加 AuthenticationScheme 属性使其失败。
像这样:
[Route("api/[controller]")]
[ApiController]
[Authorize(AuthenticationSchemes = "Basic")]
public class ValuesController : ControllerBase
这样不行。它应该默认失败,而不是必须将它添加到每个控制器。
更新二:
向 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 所建议,但 returned
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.
您需要将 [Authorize]
属性添加到您的控制器,以便授权实际对其结果执行任何操作。您可以像这样全局添加它:
services.AddMvc(config =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
config.Filters.Add(new AuthorizeFilter(policy));
});
最终解决方案使用AddMVC。解决方案是除了添加scheme之外,scheme还需要一个requirement
这个works-ish。如果我不发送任何验证 header,它 return 就是一个空白页面。如果我发送过期的 header,那么它会发送 500。应该是 401。但它不会 return 任何值,这才是我真正关心的。
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));
});
我正在为我的 ASP.NET 核心 API 创建身份验证方案。
它调用我的处理程序并命中断点,但即使授权失败,API 调用仍然会产生 return 结果。
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
if (!Request.Headers.ContainsKey(AuthorizationHeaderName))
{
//Authorization header not in request
return AuthenticateResult.Fail("Missing Authorization header");
}
以我天真的理解,如果身份验证失败,它不应该 return 数据。
我错过了什么?
详情
我在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);
}
}
}
这里是不正确 returning 结果的控制器。
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 调用仍然 returning 结果,即使它未通过身份验证。
更新:
向控制器添加 AuthenticationScheme 属性使其失败。
像这样:
[Route("api/[controller]")]
[ApiController]
[Authorize(AuthenticationSchemes = "Basic")]
public class ValuesController : ControllerBase
这样不行。它应该默认失败,而不是必须将它添加到每个控制器。
更新二:
向 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 所建议,但 returned
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.
您需要将 [Authorize]
属性添加到您的控制器,以便授权实际对其结果执行任何操作。您可以像这样全局添加它:
services.AddMvc(config =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
config.Filters.Add(new AuthorizeFilter(policy));
});
最终解决方案使用AddMVC。解决方案是除了添加scheme之外,scheme还需要一个requirement
这个works-ish。如果我不发送任何验证 header,它 return 就是一个空白页面。如果我发送过期的 header,那么它会发送 500。应该是 401。但它不会 return 任何值,这才是我真正关心的。
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));
});