Аутентификация ASP.NET Core Web API, разрешающая несанкционированный доступ - PullRequest
0 голосов
/ 11 июля 2019

Я создаю схему аутентификации для моего 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.

Ответы [ 2 ]

1 голос
/ 13 июля 2019

Вам нужно будет добавить атрибут [Authorize] в ваши контроллеры, чтобы авторизация действительно что-то делала со своим результатом.Вы можете добавить его глобально, как это:

services.AddMvc(config =>
{
    var policy = new AuthorizationPolicyBuilder()
                 .RequireAuthenticatedUser()
                 .Build();
    config.Filters.Add(new AuthorizeFilter(policy));
});
0 голосов
/ 17 июля 2019

В окончательном разрешении используется AddMVC.Решение состояло в том, что в дополнение к добавлению схемы к схеме требовалось требование.

Это работает.Если я не отправляю какой-либо заголовок аутентификации, он возвращает пустую страницу.Если я отправляю заголовок с истекшим сроком действия, он отправляет 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));
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...