request.IsPasswordGrantType () всегда дает сбой в openiddict в ASP. NET Core 3.1 - PullRequest
1 голос
/ 17 января 2020

У меня есть ASP.NET Core 2.2 веб-API с уже настроенным openiddict. Теперь после обновления проекта до asp.net core 3.1 с openiddict 2.0.1, request.IsPasswordGrantType() всегда терпит неудачу в моей конечной точке токена.

Вот мои ConfigureServices() в Startup.cs,

services.AddDbContext<AppIdentityDbContext>(options => {
    options.UseInMemoryDatabase("Identity");
    options.UseOpenIddict<Guid>();
});

// Add OpenIddict services
services.AddOpenIddict()
    .AddCore(options =>
    {
        options.UseEntityFrameworkCore()
            .UseDbContext<AppIdentityDbContext>()
            .ReplaceDefaultEntities<Guid>();
    })
    .AddServer(options =>
    {
        //options.UseMvc();

        options.EnableTokenEndpoint("/api/token");

        options.AllowPasswordFlow();
        options.AcceptAnonymousClients();
    })
    .AddValidation();

// ASP.NET Core Identity should use the same claim names as OpenIddict
services.Configure<IdentityOptions>(options =>
{
    options.ClaimsIdentity.UserNameClaimType = OpenIdConnectConstants.Claims.Name;
    options.ClaimsIdentity.UserIdClaimType = OpenIdConnectConstants.Claims.Subject;
    options.ClaimsIdentity.RoleClaimType = OpenIdConnectConstants.Claims.Role;
});

services.AddAuthentication(options =>
{
    options.DefaultScheme = OpenIddictValidationDefaults.AuthenticationScheme;
});

Вот мой Configure() метод в Startup.cs,

if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseExceptionHandler(appBuilder =>
    {
        appBuilder.Run(async context =>
        {
            context.Response.StatusCode = 500;
            await context.Response.WriteAsync("An unexpected fault happened. Try again later.");
        });
    });
}

app.UseHttpsRedirection();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
});

Вот мой TokenExchangeEndPoint в TokenController,

[HttpPost(Name = nameof(TokenExchange))]
[ProducesResponseType(200)]
[ProducesResponseType(400)]
public async Task<IActionResult> TokenExchange([FromForm]OpenIdConnectRequest request)
{
    if (!request.IsPasswordGrantType())
    {
        return BadRequest(new OpenIdConnectResponse
        {
            Error = OpenIdConnectConstants.Errors.UnsupportedGrantType,
            ErrorDescription = "The specified grant type is not supported."
        });
    }

    var user = await _userManager.FindByNameAsync(request.Username);
    if (user == null)
    {
        return BadRequest(new OpenIdConnectResponse
        {
            Error = OpenIdConnectConstants.Errors.InvalidGrant,
            ErrorDescription = "The username or password is invalid."
        });
    }

    // Ensure the user is allowed to sign in
    if (!await _signInManager.CanSignInAsync(user))
    {
        return BadRequest(new OpenIdConnectResponse
        {
            Error = OpenIdConnectConstants.Errors.InvalidGrant,
            ErrorDescription = "The specified user is not allowed to sign in."
        });
    }

    // Ensure the user is not already locked out
    if (_userManager.SupportsUserLockout && await _userManager.IsLockedOutAsync(user))
    {
        return BadRequest(new OpenIdConnectResponse
        {
            Error = OpenIdConnectConstants.Errors.InvalidGrant,
            ErrorDescription = "The username or password is invalid."
        });
    }

    // Ensure the password is valid
    if (!await _userManager.CheckPasswordAsync(user, request.Password))
    {
        if (_userManager.SupportsUserLockout)
        {
            await _userManager.AccessFailedAsync(user);
        }

        return BadRequest(new OpenIdConnectResponse
        {
            Error = OpenIdConnectConstants.Errors.InvalidGrant,
            ErrorDescription = "The username or password is invalid."
        });
    }

    // Reset the lockout count
    if (_userManager.SupportsUserLockout)
    {
        await _userManager.ResetAccessFailedCountAsync(user);
    }

    // Look up the user's roles (if any)
    var roles = new string[0];
    if (_userManager.SupportsUserRole)
    {
        roles = (await _userManager.GetRolesAsync(user)).ToArray();
    }

    // Create a new authentication ticket w/ the user identity
    var ticket = await CreateTicketAsync(request, user, roles);

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

Вот мой запрос скрипача,

Fiddler Request

Я использую Content-Type как application/x-www-form-urlencoded.

Я новичок в openiddict. Пожалуйста, помогите мне в том, что я делаю неправильно. Будем весьма благодарны за любые ссылки для openiddict образца с asp.net core 3.x.

1 Ответ

2 голосов
/ 18 января 2020

OpenIdConnectRequest не предназначен для использования с [FromForm], так как он должен разрешаться из контекста HTTP (после проверки и заполнения OpenIddict), который требует регистрации связывателей MVC с использованием options.UseMvc().

2 варианта решения вашей проблемы:

  • Раскомментируйте options.UseMvc() и удалите [FromForm]. Это будет работать с OpenIddict 2.x, но не будет поддерживаться в 3.x, где вам будет предложено использовать другую опцию.

  • Удалите параметр OpenIdConnectRequest и разрешите запрос, используя var request = HttpContext.GetOpenIdConnectRequest(). В этом случае вы можете удалить options.UseMvc().

...