Я создаю схему аутентификации для моего 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 все еще возвращает результаты, даже если он не проходит аутентификацию.
Обновление:
Добавление атрибута AuthenticationScheme к контроллеру приводит к сбою.
Как это:
[Route("api/[controller]")]
[ApiController]
[Authorize(AuthenticationSchemes = "Basic")]
public class ValuesController : ControllerBase
Это не хорошо. По умолчанию он должен завершиться сбоем вместо того, чтобы добавлять его к каждому контроллеру.
Обновление 2:
Добавление фильтра к сервисам. AddMvc выглядит многообещающе, но это тоже не работает. В документации утверждается, что вам не нужно реализовывать фильтр авторизации, поскольку они включены. Не то, чтобы я мог найти.
Я унаследовал от AuthorizeAttribute, используя идею от Matti Price и IFilterMetadata, требуемые AddMvc. Это компилируется, но все же разрешает несанкционированный доступ.
public class BasicAuthorizeAttribute : AuthorizeAttribute, IFilterMetadata { }
services.AddMvc(options => {
options.Filters.Add(typeof(BasicAuthorizeAttribute));
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
Обновление 3:
Попробовал
policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser()
как предложил Матти, но это вернуло
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.