使用服务器端 Blazor,如何在连接到 SQL 服务器数据库时使用 windows 身份验证模拟用户?

Using Server side Blazor, how do you impersonate a user using windows authentication when connecting to a SQL Server database?

我已经在我的数据库中设置了行级安全性,并且正在尝试创建到数据库的连接。我在执行此操作时遇到了麻烦,因为我似乎无法向作为请求客户端的 SQL 服务器发出请求。

应用程序是使用 Blazor 构建的,我的数据库连接是使用 EF Core 完成的。

用于运行数据库查询的服务器端方法如下

using System;
using System.Linq;
using System.Security.Principal;
using System.Threading.Tasks;
using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;

public WeatherForecastService(IConfiguration configuration, IHttpContextAccessor httpContextAccessor, IDbContextFactory<SqlDboDbContext> dbo)
{
        _httpContextAccessor = httpContextAccessor;
        _dbo = dbo;
        var context = _httpContextAccessor.HttpContext;
        Name1 = context.User.Identity.Name;

        WindowsIdentity.RunImpersonated(WindowsIdentity.GetCurrent().AccessToken, () =>
        {
            Name2 = _httpContextAccessor.HttpContext.User.Identity.Name;
            var optionsBuilder = new DbContextOptionsBuilder<SqlDboDbContext>();
            optionsBuilder.UseSqlServer(configuration.GetConnectionString("SQL_Server"));
            using (var cntx = new SqlDboDbContext(optionsBuilder.Options))
            {
                Markets = cntx.Markets.ToArray();
                t1 = cntx.Transactions.ToArray();
            }
        });
}

Name1Name2 都显示客户端,但是当我使用

查看数据库上的查询 运行 时
SELECT sdest.DatabaseName 
    ,sdes.session_id
    ,sdes.[host_name]
    ,sdes.[program_name]
    ,sdes.client_interface_name
    ,sdes.login_name
    ,sdes.original_login_name
    ,sdes.login_time
    ,sdes.nt_domain
    ,sdes.nt_user_name
    ,sdec.client_net_address
    ,sdec.local_net_address
    ,sdest.ObjName
    ,sdest.Query
FROM sys.dm_exec_sessions AS sdes
INNER JOIN sys.dm_exec_connections AS sdec ON sdec.session_id = sdes.session_id
CROSS APPLY (
    SELECT db_name(dbid) AS DatabaseName
        ,object_id(objectid) AS ObjName
        ,ISNULL((
                SELECT TEXT AS [processing-instruction(definition)]
                FROM sys.dm_exec_sql_text(sdec.most_recent_sql_handle)
                FOR XML PATH('')
                    ,TYPE
                ), '') AS Query

    FROM sys.dm_exec_sql_text(sdec.most_recent_sql_handle)
    ) sdest

--and sdes.nt_user_name = '' -- Put the username here !
ORDER BY sdec.session_id

所有字段都显示我为应用程序池设置的用户。

我尝试过的各种连接字符串:

"SQL_Server": "Data Source=[SQL server Address];Initial Catalog=Investment_Dev;Integrated Security=True;Trusted_Connection=true"

"SQL_Server": "Data Source=[SQL server Address];Initial Catalog=Investment_Dev;Integrated Security=SSPI;Trusted_Connection=true"

我的IIS配置如下

Authentication 中所有设置为 Disabled 除了 Windows Authentication 设置为 Enabled.

Configuration Editor -> system.webServer/security/authentication/windowsAuthentication 我已经将 useAppPoolCredentials 设置为 False

对于我的站点 Edit Site,我将 Connect As 设置为 Application user (pass-through authentication)

在我的应用程序池中,我将池 Managed pipeline mode 设置为 IntegratedIdentity 设置为我设置的用于处理传入请求的服务帐户,Load User Profile 设置为 False 我试过设置为 True

虽然我在上面的方法中重新创建了一个新的 dbcontext 来测试解决方案,但我的应用程序通常确实使用 DbContextFactory 从数据库中获取数据。

Startup.cs 中,我按以下方式进行了设置。

using Impersonation_Test_Project.Data;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.EntityFrameworkCore;

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddRazorPages();
        services.AddServerSideBlazor();
        services.AddSingleton<WeatherForecastService>();
        services.AddDbContextFactory<SqlDboDbContext>(opt => opt
            .UseLazyLoadingProxies()
            
            .UseSqlServer(Configuration.GetConnectionString("SQL_Server")));
        services.AddHttpContextAccessor();
    }

Windows Auth 并不意味着模仿。所以通常你的代码作为你的应用程序池标识运行,所以这就是 WindowsIdentity.GetCurrent() returns.

参见例如,ASP.NET Impersonation Authentication

您可以使用 SQL 服务器行级安全性而无需模拟,如 here. Or you can grant your App Pool identity the privilege to perform SQL Server impersonation of your end users, and impersonate them inside SQL Server using EXECUTE AS 中所述,而不是 Windows 中的解释。