在 IS4 中实施和验证 Db 用户而不是测试用户的正确方法是什么?

What is the right way for implement and authenticate Db Users in IS4 instead of Test Users?

我正在研究微服务并实现混合流。我的项目在测试用户中运行良好。 但我需要让它更加动态并验证我的数据库用户而不是测试用户。

我在这里分享我的认证项目startup.cs文件代码,我已经试过了:

public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection")));

        services.AddControllersWithViews();

        services.AddIdentity<User, Role>()
            .AddRoles<Role>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();

        var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;

        services.AddIdentityServer()
            .AddDeveloperSigningCredential()
            .AddConfigurationStore(options =>
            {
                options.ConfigureDbContext = builder =>
                    builder.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
                        sql => sql.MigrationsAssembly(migrationsAssembly));
            })
            // this adds the operational data from DB (codes, tokens, consents)
            .AddOperationalStore(options =>
            {
                options.ConfigureDbContext = builder =>
                    builder.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
                        sql => sql.MigrationsAssembly(migrationsAssembly));
            });
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseStaticFiles();
        app.UseRouting();
        app.UseIdentityServer();
        app.UseAuthorization();

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

运行使用上述代码后,我无法登录我的身份验证服务器

控制台上没有显示错误window

浏览器控制台也一样

如果我 运行 下面的代码工作正常并且系统让我登录怎么办

public void ConfigureServices(IServiceCollection services)
    {

        services.AddControllersWithViews();

        var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;

        services.AddIdentityServer()
            .AddDeveloperSigningCredential()
            .AddTestUsers(Config.TestUsers)
            .AddConfigurationStore(options =>
            {
                options.ConfigureDbContext = builder =>
                    builder.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
                        sql => sql.MigrationsAssembly(migrationsAssembly));
            })
            // this adds the operational data from DB (codes, tokens, consents)
            .AddOperationalStore(options =>
            {
                options.ConfigureDbContext = builder =>
                    builder.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
                        sql => sql.MigrationsAssembly(migrationsAssembly));
            });
    }

我在上面的代码中遗漏了什么?从数据库而不是使用测试用户验证用户的正确方法是什么?

我找到了我的问题答案,但奇怪的是,Identity Server 4 官方文档没有提供任何用于将测试用户切换为实际用户并在 UI 级别进行调整的文档。

答案是:

修改登录页面内容

Quickstart/Account/AccountController.cs处可以看到构造函数中注入了TestUser。删除它并注入以下内容:

替换为:

private readonly TestUserStore _users;

有了这个:

private readonly UserManager<User> _userManager;
private readonly SignInManager<User> _signInManager;

在构造函数中,替换如下:

IIdentityServerInteractionService interaction,
            IClientStore clientStore,
            IAuthenticationSchemeProvider schemeProvider,
            IEventService events,
            TestUserStore users = null)
        {
            _users = users ?? new TestUserStore(TestUsers.Users);
            _interaction = interaction;
            _clientStore = clientStore;
            _schemeProvider = schemeProvider;
            _events = events;
        }

有了这个:

public AccountController(
            UserManager<User> userManager,
            SignInManager<User> signInManager,
            IIdentityServerInteractionService interaction,
            IClientStore clientStore,
            IAuthenticationSchemeProvider schemeProvider,
            IEventService events)
        {
            _userManager = userManager;
            _signInManager = signInManager;
            _interaction = interaction;
            _clientStore = clientStore;
            _schemeProvider = schemeProvider;
            _events = events;
        }

找到登录post动作,修改登录验证逻辑。

if (ModelState.IsValid)
{
    var result = await _signInManager.PasswordSignInAsync(model.Username, model.Password, model.RememberLogin, lockoutOnFailure: true);
    if (result.Succeeded)
    {
        var user = await _userManager.FindByNameAsync(model.Username);
        await _events.RaiseAsync(new UserLoginSuccessEvent(user.UserName, user.Id.ToString(), user.UserName));

        if (context != null)
        {
            if (await _clientStore.IsPkceClientAsync(context.Client.ClientId))
            {
                // if the client is PKCE then we assume it's native, so this change in how to
                // return the response is for better UX for the end user.
                return View("Redirect", new RedirectViewModel { RedirectUrl = model.ReturnUrl });
            }

            // we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
            return Redirect(model.ReturnUrl);
        }

        // request for a local page
        if (Url.IsLocalUrl(model.ReturnUrl))
        {
            return Redirect(model.ReturnUrl);
        }
        else if (string.IsNullOrEmpty(model.ReturnUrl))
        {
            return Redirect("~/");
        }
        else
        {
            // user might have clicked on a malicious link - should be logged
            throw new Exception("invalid return URL");
        }
    }

    await _events.RaiseAsync(new UserLoginFailureEvent(model.Username, "invalid credentials"));
    ModelState.AddModelError(string.Empty, AccountOptions.InvalidCredentialsErrorMessage);
}

Quickstart/Extensions.cs 添加以下代码

public static async Task<bool> IsPkceClientAsync(this IClientStore store, string client_id)
{
    if (!string.IsNullOrWhiteSpace(client_id))
    {
        var client = await store.FindEnabledClientByIdAsync(client_id);
        return client?.RequirePkce == true;
    }

    return false;
}

原始答案与旧的修改:

In Identity Server 4, how to add actual users, not test users