Asp.net core 如何与IdentityServer4中的非标准用户存储接口?

Asp.net core 如何与IdentityServer4中的非标准用户存储接口?,asp.net-core,owin,identityserver4,Asp.net Core,Owin,Identityserver4,我想使用IdentityServer4实现OIDC身份验证,以供将来开发。我们有一个在Asp.Net成员身份或Asp.Net标识之前实现的现有自制成员身份模式。我们有使用现有成员模式对用户进行身份验证和授权的遗留应用程序 如何为用户存储实现指向旧模式的适配器(假设用户表中有用户名和密码列)?我看到的唯一例子是内存用户和AspnetIdentity。要与您自己的用户存储集成,您需要创建IProfileService的实现(如果需要使用资源所有者授权类型,还可以选择IResourceOwnerPas

我想使用IdentityServer4实现OIDC身份验证,以供将来开发。我们有一个在Asp.Net成员身份或Asp.Net标识之前实现的现有自制成员身份模式。我们有使用现有成员模式对用户进行身份验证和授权的遗留应用程序


如何为用户存储实现指向旧模式的适配器(假设用户表中有用户名和密码列)?我看到的唯一例子是内存用户和AspnetIdentity。

要与您自己的用户存储集成,您需要创建
IProfileService
的实现(如果需要使用资源所有者授权类型,还可以选择
IResourceOwnerPasswordValidator
),然后在IServiceCollection中注册它


e、 g:
services.AddTransient()

我需要适应IdentityServer4的传统系统需要三条信息来验证用户:公司标识符、用户名和密码

我们的系统有一个主数据库和一个companys表,该表包含到公司特定数据库(租户)的连接字符串。每个租户数据库都有一个用户表,其中包含用户配置文件信息,包括用户名和密码

使用Scott Brady的答案,我能够实现一个适用于我们的情况的
IResourceOwnerPasswordValidator
,但必须深入研究IdentityModel.TokenClient源代码。我发现的是令牌端点(令牌\u端点:http:///connect/token)采用URL编码形式,序列化键/值对,并通过
ResourceOwnerPasswordValidationContext
参数的
Request.Raw
属性在
IResourceOwnerPasswordValidator.ValidateAsync
中提供它们

下面是我的
ResourceOwnerPasswordValidator.ValidateAsync()
实现的一个示例,展示了如何使用用户名和密码以外的其他参数进行身份验证:

public Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
{
     _logger.LogInformation("Begin resource owner password validation.");

     var username = context.UserName;
     var password = context.Password;
     var company = context.Request.Raw.Get("company");

     if (string.IsNullOrWhiteSpace(company))
     {
          _logger.LogError("'company' doesn't exist in ResourceOwnerPasswordValidationContext.Request.Raw collection.");
          context.Result = new GrantValidationResult(TokenRequestErrors.InvalidRequest, "Company is required.");
           return Task.FromResult(0);
      }

      if (string.IsNullOrWhiteSpace(username))
      {
           _logger.LogError("'username' is null or whitespace.");
           context.Result = new GrantValidationResult(TokenRequestErrors.InvalidRequest, "Username is required.");
           return Task.FromResult(0);
      }

      var userRepo = _userRepositoryFactory.GetUserRepositoryForCompany(company);
      var user = userRepo.GetUserByUserId(username);

      if (user == null)
      {
           _logger.LogError($"No user found for company {company} and username {username}.");
           context.Result = new GrantValidationResult(TokenRequestErrors.InvalidRequest, $"No user {username} found for for {company}.");
           return Task.FromResult(0);
       }

       _logger.LogInformation("Resource owner password validation succeeded.");
        context.Result = user.Password == password ? new GrantValidationResult(context.UserName, GrantType.ResourceOwnerPassword, new [] { new Claim("company", company) }) : new GrantValidationResult(TokenRequestErrors.InvalidRequest, "Invalid username or password.");

        return Task.FromResult(0);
  }
我使用Postman通过点击令牌端点来验证我的结果。首先,我在IdentityServer4实现中配置了一个客户端:

new Client {
    AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
    AllowedScopes = {
        IdentityServerConstants.StandardScopes.OpenId,
        IdentityServerConstants.StandardScopes.Profile,
        IdentityServerConstants.StandardScopes.Email
    },
    ClientId = "test.client",
    ClientName = "Test Client",
    ClientSecrets = new List<Secret>
    {
        new Secret("secret".Sha256())
    }
}
新客户端{
AllowedGrantTypes=GrantTypes.ResourceOwnerPassword,
允许范围={
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email
},
ClientId=“test.client”,
ClientName=“测试客户端”,
ClientSecrets=新列表
{
新密码(“Secret.Sha256())
}
}
在Postman中,我为授权类型选择了基本身份验证。用户名是客户端ID,密码是客户端密码。我将动词设置为POST,并指定了一个“x-www-form-urlencoded”主体。端点需要用户名、密码、授权类型和作用域的最小值。我添加了一个公司密钥/值参数:


我也有类似的实现要求,但使用带有租户:company1的acr_值头作为公司标识符会不会更麻烦?

谢谢你的提示,我找到了一个很好的方法,它准确地描述了如何实现
IResourceOwnerPasswordValidator
IProfileService
,但我还有一个问题,希望你能帮我。是否可以在登录表单中添加另一个字段?传统系统中的用户由公司、用户名和密码标识。我需要让公司从登录到
ResourceOwnerPasswordValidator
,以便唯一地选择用户。无论如何,我在AccountController上使用作为修改登录页面和登录操作的基础,以使用公司值以及用户名和密码。我真的不太了解CORS,但我不认为访问控制头在这种情况下有用。首先,我不确定传递附加标识参数是否合适。我们用户的主键实际上是公司+用户名。但是我也不认为可以从
ResourceOwnerPasswordValidator.ValidateAsync()
方法中访问这些头。根据我在下面发布的代码,
var company=context.Request.Raw.Get(“company”),Raw是原始请求正文内容的NameValueCollection。