【问题标题】:Identity Server 4: Request Password Token Async with DB userIdentity Server 4:请求与 DB 用户同步的密码令牌
【发布时间】:2021-10-09 17:46:04
【问题描述】:

我在理解和使我的应用程序与 Identity Server 4 一起工作时遇到了一些麻烦。我想使用数据库中的用户生成验证令牌。使用 TestUser 一切正常,所以我确定我错过了一些东西。

我将从我的用户模型开始,我将其命名为“ApplicationUser”:

public class ApplicationUser : IdentityUser
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public string UserName { get; set; }
    public string AvatarUrl { get; set; }
    public byte[] PasswordHash { get; set; }
    public byte[] PasswordSalt { get; set; }
}

通过这个模型类,我完成了用户注册和用户登录。

    public async Task<ServiceResponse<int>> Register(ApplicationUser user, string password)
    {
        ServiceResponse<int> response = new ServiceResponse<int>();
        if (await UserExists(user.Email))
        {
            response.Success = false;
            response.Message = "User already exists.";
            return response;
        }
        else
        {
            CreatePasswordHash(password, out byte[] passwordHash, out byte[] passwordSalt);

            user.PasswordHash = passwordHash;
            user.PasswordSalt = passwordSalt;
            user.UserName = user.Email;

            _context.ApplicationUsers.Add(user);
            await _context.SaveChangesAsync();
            response.Data = user.Id;
            return response;
        }
    }

    public async Task<ServiceResponse<string>> Login(string email, string password)
    {
        var response = new ServiceResponse<string>();
        var user = await _context.ApplicationUsers.FirstOrDefaultAsync(x => x.Email.ToLower().Equals(email.ToLower()));
        if (user == null)
        {
            response.Success = false;
            response.Message = "User not found.";
        }
        else if (!VerifyPasswordHash(password, user.PasswordHash, user.PasswordSalt))
        {
            response.Success = false;
            response.Message = "Wrong password.";
        }
        else
        {
            response.Data = await CreateToken(email, password);
        }

        return response;
    }

“CreateToken”方法是我请求令牌的地方,它看起来像这样:

    private async Task<string> CreateToken(string username, string password)
    {
        var client = new HttpClient();
        var disco = await client.GetDiscoveryDocumentAsync("https://localhost:5001");

        if (disco.IsError)
        {
            Console.WriteLine(disco.Error);
        }

        var tokenResponse = await client.RequestPasswordTokenAsync(new PasswordTokenRequest
        {
            Address = disco.TokenEndpoint,

            ClientId = "ro.client",
            ClientSecret = "SuperSecretPassword",

            UserName = username,
            Password = password,

            Scope = "task-app"
        });

        if (tokenResponse.IsError)
        {
            Console.WriteLine(tokenResponse.Error);
        }

        Console.WriteLine(tokenResponse.Json);

        return tokenResponse.Json.ToString();
    }

ConfigureServices 的 Startup.cs 代码是这样的:

    public void ConfigureServices(IServiceCollection services)
    {
        var connectionString = Configuration.GetConnectionString("DefaultConnection");
        var migrationAssembly = typeof(Startup).Assembly.GetName().Name;

        services.AddDbContext<DataContext>(options => options.UseMySQL(connectionString));

        //services.AddDbContext<DataContext>(options =>
        //    options.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationAssembly)));

        services.AddCors(options =>
        {
            options.AddDefaultPolicy(
                builder =>
                {
                    builder
                    .AllowAnyHeader()
                    .AllowAnyMethod()
                    .AllowCredentials();
                });
            options.AddPolicy("AllowAllHeaders",
                builder =>
                {
                    builder
                    .AllowAnyOrigin()
                    .AllowAnyHeader()
                    .AllowAnyMethod();
                });
        });

        services.AddControllers();

        services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("v1", new OpenApiInfo { Title = "Auth", Version = "v1" });
            c.AddSecurityDefinition("oath2", new OpenApiSecurityScheme
            {
                Description = "Standard Authorization header using the Bearer schema. Example: \"bearer {token}\"",
                In = ParameterLocation.Header,
                Name = "Authorization",
                Type = SecuritySchemeType.ApiKey
            });
            c.OperationFilter<SecurityRequirementsOperationFilter>();
        });


        services.AddIdentityServer()
            //Configuration Store: clients and resources
            .AddConfigurationStore(options =>
            {
                options.ConfigureDbContext = builder => builder.UseMySQL(connectionString, opt => opt.MigrationsAssembly(migrationAssembly));
            })
            //Oprerationals Store: tokens, consets, codes, etc
            .AddOperationalStore(options =>
            {
                options.ConfigureDbContext = builder => builder.UseMySQL(connectionString, opt => opt.MigrationsAssembly(migrationAssembly));
            })
            .AddAspNetIdentity<ApplicationUser>()
            .AddDeveloperSigningCredential();

        services.AddIdentity<ApplicationUser, IdentityRole>()
                .AddEntityFrameworkStores<DataContext>()
                .AddDefaultTokenProviders();

        services.AddScoped<IAuthRepository, AuthRepository>();

    }

最后我的 Identity Server 配置类是这样的:

    public static class Config
{
    public static List<TestUser> GetUsers()
    {
        return new List<TestUser>
        {
            new TestUser
            {
                SubjectId = "1",
                Username = "test1",
                Password = "123"
            },

            new TestUser
            {
                SubjectId = "2",
                Username = "test2",
                Password = "123"
            }
        };
    }

    public static IEnumerable<IdentityResource> IdentityResources => new[]
    {
        new IdentityResources.OpenId(),
        new IdentityResources.Profile(),
        new IdentityResource
        {
          Name = "role",
          UserClaims = new List<string> {"role"}
        }
    };

    public static IEnumerable<ApiScope> ApiScopes => new[]
    {
        new ApiScope( "task-app" ),
    };

    public static IEnumerable<ApiResource> ApiResources => new[]
    {
        new ApiResource("task-app")
        {
            Scopes = new List<string> { "task-app" },
            ApiSecrets = new List<Secret> {new Secret("ScopeSecret".Sha256())},
            UserClaims = new List<string> { "role" }
        }
    };

    public static IEnumerable<Client> Clients => new[]
    {
        new Client
        {
          ClientId = "ro.client",
          ClientName = "Client Credentials Client",

          AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
          ClientSecrets = {new Secret("SuperSecretPassword".Sha256())},

          AllowedScopes = { "task-app" }
        }
    };
}

注册和登录方法对于简单用户来说很简单。我是否需要自定义实现注册和登录才能与 Identity Server 4 一起使用?

我是否遗漏了我的 Config 文件或 Startup 类中的某些内容?

非常感谢您的宝贵时间和帮助!

【问题讨论】:

    标签: c# database identityserver4


    【解决方案1】:

    您必须在 startup.cs 中添加包含 Asp Net 表的上下文:

    var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
    
     services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(identityConnectionString, sql => sql.MigrationsAssembly(migrationsAssembly)));
    

    【讨论】:

    • 我有这样的东西:` var connectionString = Configuration.GetConnectionString("DefaultConnection");` var migrationAssembly = typeof(Startup).Assembly.GetName().Name; services.AddDbContext&lt;DataContext&gt;(options =&gt; options.UseMySQL(connectionString)); 如果我把你的代码我得到一个错误:services.AddIdentityServer()。错误是:System.InvalidOperationException: 'Service type: IUserClaimsPrincipalFactory1 未注册。'` 我不知道下一步该做什么。 (PS 抱歉编辑过多。我不知道如何格式化此评论)
    • 如果您使用声明工厂,则必须将其添加到身份:.AddClaimsPrincipalFactory()
    • 对不起,我不太明白。我编辑了我的答案,并在那里复制了所有的 ConfigureServices 方法。有什么我想念的吗?
    猜你喜欢
    • 2021-03-01
    • 2018-06-01
    • 1970-01-01
    • 2019-05-24
    • 2020-08-05
    • 2018-02-21
    • 1970-01-01
    • 2019-06-06
    • 2017-06-29
    相关资源
    最近更新 更多