Как использовать Basi c Auth в netcore 2.2 - PullRequest
0 голосов
/ 21 февраля 2020

Мне нужно создать простой сервис Netcore 2.2 (построенный как библиотека), который должен использовать базовый c auth. Файл проекта:

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net462</TargetFramework>
    <OutputType>Library</OutputType>

    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
    <OutDir>$(SolutionDir)bin\$(Configuration)\Modules\WebDataExport</OutDir>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore" Version="2.2.0" />
    <PackageReference Include="Microsoft.AspNetCore.Authentication" Version="2.2.0" />
    <PackageReference Include="Microsoft.AspNetCore.Authorization" Version="2.2.0" />
    <PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="2.2.0" />
    <PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.2.0" />
    <PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.0" />
    <PackageReference Include="Microsoft.AspNetCore.Routing" Version="2.2.0" />
    <PackageReference Include="Microsoft.Extensions.Logging" Version="2.2.0" />
    <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.2.0" />
  </ItemGroup>

  <ItemGroup>
    <Reference Include="System.ComponentModel.Composition" />
  </ItemGroup>

</Project>

Строитель:

public IWebHost BuildWebHost(string[] args)
{
    var path = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);

    var config = new ConfigurationBuilder()
        .SetBasePath(path)
        .AddJsonFile("appsettings.json", optional: false)
        .Build();

    var webHost = WebHost.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration((hostingContext) =>
        {
        })
        .ConfigureServices(services =>
        {
            services.AddMvcCore().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

            // configure basic authentication 
            services.AddAuthentication("BasicAuthentication")
                .AddScheme<AuthenticationSchemeOptions, BasicAuthenticationHandler>("BasicAuthentication", null);

            // Add service for data access
            services.AddSingleton(_dataProvider);
        })
        .Configure(app =>
        {
            app.UseAuthentication();
            app.UseMvc();
        })
        .UseUrls($"http://*:{config.GetValue<int>("ListenPort")}")
        .UseKestrel();

    return webHost.Build();
}

И мой контроллер:

[Authorize]
[ApiController]
[Route("[controller]")]
[Produces("application/json")]
public class GetRecordingsController : ControllerBase
{
    public GetRecordingsController(ILogger<GetRecordingsController> logger, IDataProvider dataProvider)
    {
    }

    [HttpGet]
    public async Task<IActionResult> Get([FromQuery] string From, 
                                         [FromQuery] string To)
    {
    }
}

И, в конце концов, это BasicAuthenticationHandler :

public class BasicAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
    private readonly IDataProvider _dataProvider;

    public BasicAuthenticationHandler(IOptionsMonitor<AuthenticationSchemeOptions> options,
                                      ILoggerFactory logger,
                                      UrlEncoder encoder,
                                      ISystemClock clock,
                                      IDataProvider dataProvider) 
        : base(options, logger, encoder, clock)
    {
        _dataProvider = dataProvider;
    }

    protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        if (!Request.Headers.ContainsKey("Authorization"))
            return AuthenticateResult.Fail("Missing Authorization Header");

        User user;
        try
        {
            var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]);
            var credentialBytes = Convert.FromBase64String(authHeader.Parameter);
            var credentials = Encoding.UTF8.GetString(credentialBytes).Split(new[] { ':' }, 2);
            var username = credentials[0];
            var password = credentials[1];                

            user = await _dataProvider.AuthenticateUser(username, password);
        }
        catch
        {
            return AuthenticateResult.Fail("Invalid Authorization Header");
        }

        if (user == null)
            return AuthenticateResult.Fail("Invalid Username or Password");

        var claims = new[] {
            new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
            new Claim(ClaimTypes.Name, user.Username),
        };
        var identity  = new ClaimsIdentity(claims, Scheme.Name);
        var principal = new ClaimsPrincipal(identity);
        var ticket    = new AuthenticationTicket(principal, Scheme.Name);

        return AuthenticateResult.Success(ticket);
    }
}

Теперь, что происходит, если я посылаю GET с неверным паролем, HandleAuthenticateAsyn c правильно возвращает fail , но я получаю метод вызывается в любом случае: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService не вызывается.

Это журнал:

info: Sinora.Modules.WebDataExport.BasicAuthenticationHandler[7]
      BasicAuthentication was not authenticated. Failure message: Invalid Username or Password
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
      Executing endpoint 'Sinora.Modules.WebDataExport.Controllers.GetRecordingsController.Get (Sinora.Modules.WebDataExport)'
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
      Route matched with {action = "Get", controller = "GetRecordings"}. Executing action Sinora.Modules.WebDataExport.Controllers.GetRecordingsController.Get (Sinora.Modules.WebDataExport)
 .....
    [METHOD EXECUTION]
 .....
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
      Executed endpoint 'Sinora.Modules.WebDataExport.Controllers.GetRecordingsController.Get (Sinora.Modules.WebDataExport)'
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
      Request finished in 11384.1282ms 200

Пока я ожидаю что-то вроде :

info: Sinora.Modules.WebDataExport.BasicAuthenticationHandler[7]
      BasicAuthentication was not authenticated. Failure message: Invalid Username or Password
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
      Executing endpoint 'Sinora.Modules.WebDataExport.Controllers.GetRecordingsController.Get (Sinora.Modules.WebDataExport)'
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
      Route matched with {action = "Get", controller = "GetRecordings"}. Executing action Sinora.Modules.WebDataExport.Controllers.GetRecordingsController.Get (Sinora.Modules.WebDataExport)

info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
      Authorization failed.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[3]
      Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
info: Microsoft.AspNetCore.Mvc.ChallengeResult[1]
      Executing ChallengeResult with authentication schemes ().
info: WebApi.Helpers.BasicAuthenticationHandler[12]
      AuthenticationScheme: BasicAuthentication was challenged.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
      Executed action Sinora.Modules.WebDataExport.Controllers.GetRecordingsController.Get (Sinora.Modules.WebDataExport) in 11062.176ms

info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
      Executed endpoint 'Sinora.Modules.WebDataExport.Controllers.GetRecordingsController.Get (Sinora.Modules.WebDataExport)'
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
      Request finished in 11384.1282ms 200

Я не могу понять, где я не прав

1 Ответ

0 голосов
/ 21 февраля 2020

Я думаю, что вы пропустили следующий вызов в вашем файле запуска

app.UseAuthorization();

Надеюсь, это решит вашу проблему.

...