Разрешить базовую авторизацию в дополнение к OpenId с помощью OpenIddict

Я правильно настроил OpenIddict, и он хорошо работает.

Теперь одно из приложений, с которыми мне нужно взаимодействовать, способно выполнять только POST someurl с заголовком авторизации. Я не контролирую это приложение.

Я попытался добавить к своему серверу еще один маршрут:

    [EnableCors]
    [HttpPost("TokensDev"), Produces("application/json")]
    public async Task<IActionResult> ExchangeDev()
    {
        if (! this.Request.Headers.TryGetValue("Authorization", out var authHeader_))
            return Unauthorized();
        var authHeader = AuthenticationHeaderValue.Parse(authHeader_);
        var credentialBytes = Convert.FromBase64String(authHeader.Parameter);
        var credentials = Encoding.UTF8.GetString(credentialBytes).Split(new[] { ':' }, 2);

        var user = await _userManager.FindByNameAsync(credentials[0]);
        if (user == null)
            return Unauthorized();

        var result = await _signInManager.CheckPasswordSignInAsync(user, credentials[1], lockoutOnFailure: true);
        if (!result.Succeeded)
            return Unauthorized();

        var principal = await _signInManager.CreateUserPrincipalAsync(user);

        var ticket = new AuthenticationTicket(principal,
            new AuthenticationProperties(),
            OpenIddictServerDefaults.AuthenticationScheme);

        foreach (var claim in ticket.Principal.Claims)
        {
            claim.SetDestinations(GetDestinations(claim, ticket));
        }

        return SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme);
    }

Но проблема в том, что OpenIddict предотвращает это:

fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
      An unhandled exception has occurred while executing the request.
System.InvalidOperationException: An authorization or token response cannot be returned from this endpoint.
   at AspNet.Security.OpenIdConnect.Server.OpenIdConnectServerHandler.SignInAsync(AuthenticationTicket ticket)
   at Microsoft.AspNetCore.Authentication.AuthenticationService.SignInAsync(HttpContext context, String scheme, ClaimsPrincipal principal, AuthenticationProperties properties)
   at Microsoft.AspNetCore.Mvc.SignInResult.ExecuteResultAsync(ActionContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeResultAsync(IActionResult result)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResultFilterAsync[TFilter,TFilterAsync]()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResultExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeResultFilters()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
   at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

Есть ли способ настроить OpenIddict для этого?

Примечание: я пытался напрямую использовать тот же метод для OpenId и базовой авторизации, однако в этом случае OpenIddict отказывается от согласования CORS ...


person Christophe Blin    schedule 14.01.2021    source источник


Ответы (1)


После многих часов изучения кода OpenIddict я нашел способ сделать то, что мне нужно.

Не думаю, что это красиво, но работает:

    [EnableCors]
    [HttpPost("TokensDev"), Produces("application/json")]
    public async Task<IActionResult> ExchangeDev()
    {
        if (! this.Request.Headers.TryGetValue("Authorization", out var authHeader_))
            return Unauthorized();
        var authHeader = AuthenticationHeaderValue.Parse(authHeader_);
        var credentialBytes = Convert.FromBase64String(authHeader.Parameter);
        var credentials = Encoding.UTF8.GetString(credentialBytes).Split(new[] { ':' }, 2);

        var request = new OpenIdConnectRequest
        {
            GrantType = "password",
            Username = credentials[0],
            Password = credentials[1],
            Scope = "openid",
        };
        request.SetProperty(OpenIdConnectConstants.Properties.MessageType, OpenIdConnectConstants.MessageTypes.TokenRequest);
        HttpContext.SetOpenIdConnectRequest(request);
        return await Exchange(); //this is the "normal" openid entry point
    }

Обратите внимание, что это работает только потому, что стороннее приложение использует свойство access_token результата JSON ...

person Christophe Blin    schedule 15.01.2021