Net Core 3.1 API с пользовательской проверкой пароля Identity Server 4

Я создаю API с использованием сервера идентификации, и мне нужно использовать существующую базу данных. Пароль пользователя хранится с пользовательским хэш-паролем. Я использую FindClientByIdAsync для проверки пользователя и пароля, но поскольку пароль зашифрован нестандартным алгоритмом, я получаю сообщение об ошибке invalid_client. Если я изменяю во время выполнения (с точкой останова) значение пароля для незашифрованного значения, аутентификация работает. Возможно ли изменить проверку client_secret для FindClientByIdAsync?

Пользовательский класс ClientStore

public class ClientStore : IClientStore
{
    private readonly IMyUserRepository myUserRepository;

    public ClientStore(IMyUserRepository myUserRepository)
    {
        this.myUserRepository = myUserRepository;
    }

    public static IEnumerable<IdentityResource> GetIdentityResources()
    {
        return new List<IdentityResource>
        {
            new IdentityResources.OpenId()
        };
    }

    public static IEnumerable<ApiResource> GetApiResources()
    {
        return new List<ApiResource>
        {
            new ApiResource("My_API", "My API")
        };
    }

    public async Task<Client> FindClientByIdAsync(string client)
    {
        var user = await myUserRepository.GetUserByEmailAsync(client);

        if (user == null)
            return null;

        return new Client()
        {
            ClientId = client,
            AllowedGrantTypes = GrantTypes.ResourceOwnerPasswordAndClientCredentials,
            ClientSecrets =
            {
                new Secret(user.Password.Sha256()) //if I change to unencrypted works, but the value in database is hashed
            },
            AllowedScopes = { "GOLACO_API", IdentityServerConstants.StandardScopes.OpenId }
        };
    }
}

Конфигурация сервера идентификации в классе Startup

services.AddIdentityServer(options =>
            {
                options.Events.RaiseSuccessEvents = true;
                options.Events.RaiseFailureEvents = true;
                options.Events.RaiseErrorEvents = true;
            })
            .AddSigningCredential(GetSigningCredential()) // here I just read the private.key file
            .AddInMemoryIdentityResources(ClientStore.GetIdentityResources())
            .AddInMemoryApiResources(ClientStore.GetApiResources())
            .AddClientStore<ClientStore>();

services.AddAuthentication("Bearer")
              .AddIdentityServerAuthentication(options =>
              {
                  options.Authority = configuration["Configuration"];
                  options.ApiName = "My_API";
                  options.RequireHttpsMetadata = false;
              });

        services.AddAuthentication()
            .AddFacebook("Facebook", options =>
            {
                options.AppId = "1234";
                options.AppSecret = "1234567890";
            });

        var policy = new AuthorizationPolicyBuilder()
               .RequireAuthenticatedUser()
               .Build();

person Tiago Crizanto    schedule 05.06.2020    source источник
comment
Вы не можете использовать FindClientByIdAsync для пользователей. Пользователь не является клиентом. Терминологию см. в документации.   -  person Ruard van Elburg    schedule 06.06.2020


Ответы (1)


Вы должны реализовать IResourceOwnerPasswordValidator, как показал Дэмиен в своем блог

public class CustomResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
{
    private readonly IUserRepository _userRepository;

    public CustomResourceOwnerPasswordValidator(IUserRepository userRepository)
    {
        _userRepository = userRepository;
    }

    public Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
    {
        if (_userRepository.ValidateCredentials(context.UserName, context.Password))
        {
            var user = _userRepository.FindByUsername(context.UserName);
            context.Result = new GrantValidationResult(user.SubjectId, OidcConstants.AuthenticationMethods.Password);
        }

        return Task.FromResult(0);
    }
}

И добавьте builder.AddResourceOwnerValidator<CustomResourceOwnerPasswordValidator>(); в файл запуска.

person Kishan Vaishnav    schedule 20.06.2020