Проверка подлинности Windows для удаленного пользователя в приложении ASP.NET Core с Entity Framework
Фон
У меня есть приложение ASP.NET Core, работающее в Http.sys для обеспечения проверки подлинности Windows.
Клиентская часть моего приложения работает с аутентификацией Windows, и при первом доступе к сайту у пользователей запрашиваются учетные данные для входа в Windows. Все хорошо с этим.
Я использую базу данных SQL Server (размещенную на том же сервере, что и приложение), которая создается Entity Framework с использованием подхода, основанного на коде. в startup.cs
файл, который я запускаю dbContext.migrate()
чтобы убедиться, что база данных обновлена, а затем приложение продолжает работать как обычно.
Проблема
Когда удаленный пользователь взаимодействует с сайтом и выполняет действие, требующее доступа к базе данных, я хотел бы, чтобы эта транзакция базы данных была выполнена под его именем пользователя.
Например, если я запускаю основное приложение Asp.net на моем сервере как User1
а затем получить доступ к веб-приложению с компьютера пользователя, который вошел в систему как User2
взаимодействие с базой данных все еще выполняется User1
поскольку это пользователь, под которым работает основное приложение.
Я бы хотел, чтобы взаимодействие с базой данных осуществлялось User2
вместо User1
в этом случае. Главным образом для целей регистрации и анализа.
При получении экземпляра dbContext
Я предоставляю ему строку подключения, в которой говорится, чтобы использовать SSPI для аутентификации. Есть ли способ включить имя пользователя удаленного пользователя в это соединение, чтобы они могли подключаться к базе данных как они сами? Я могу легко получить учетные данные / имя пользователя удаленного пользователя из моего контроллера. Я верю, что могу использовать то, что называется Impersonation
но я не уверен в лучших практиках реализации этого или если это рекомендуемое решение.
Любая помощь будет принята с благодарностью.
Обновить
Благодаря некоторым полезным отзывам я попытался реализовать следующее:
Моя строка подключения установлена как в startup.cs
:
services.AddDbContext<MyDbContext>(options => options.UseSqlServer(@"Server=MyServer\MSSQLSERVER;Database=MyDatabase;Trusted_Connection=True;"));
Затем я выполняю такое действие в своем контроллере / классе:
var values = new List<Values>();
WindowsIdentity.RunImpersonated(user.AccessToken, () =>
{
var optionsBuilder = new DbContextOptionsBuilder<MyDbContext>();
optionsBuilder.UseSqlServer(@"Server=MyServer\MSSQLSERVER;Database=MyDatabase;Trusted_Connection=True;");
using (var ctx = new MyDbContext(optionsBuilder.Options))
{
values = (from row in ctx.Table select row).OrderBy(x => x.Id).ToList();
}
});
user
переменная передается в функцию и имеет тип WindowsIdentity
,
Выполнение кода из localhost работает нормально, но затем, когда удаленный пользователь пытается это сделать, он возвращает следующую ошибку: System.Data.SqlClient.SqlException: 'A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: TCP Provider, error: 0 - No such host is known.)
Обновление 2
Мне удалось устранить эту ошибку, используя IP-адрес для строки подключения вместо имени сервера / компьютера. Теперь моя строка подключения выглядит так:@"Server=<IP address>\MSSQLSERVER;Database=ConfigDb;Trusted_Connection=True
Теперь я столкнулся с другой проблемой, когда SQL Server заявляет, что No connection could be made because the target machine actively refused it
, Я могу подключиться к SQL Server, используя этого пользователя через SQL Management Studio, но не через мое приложение.
Я обнаружил в EventViewer, что фактическая ошибка связана с SSPI: SSPI handshake failed with error code 0x8009030c, state 14 while establishing a connection with integrated security; the connection has been closed. Reason: AcceptSecurityContext failed. The operating system error code indicates the cause of failure. The logon attempt failed [CLIENT: <named pipe>]
, Не совсем уверен, почему это не получится.
2 ответа
Базовые документы ASP.NET охватывают именно эту тему.
Проще говоря, ASP.NET Core не реализует олицетворение. Это пример обходного пути с использованием WindowsIdentity
но он имеет свои ограничения и должен использоваться только для относительно простых операций.
Существует также пакет NuGet, который может помочь вам получить больше функциональности, но все еще ограничен.
Есть ли способ включить имя пользователя удаленного пользователя в это соединение, чтобы они могли подключаться к базе данных как они сами?
Это не будет работать с предоставлением только имени пользователя для строки подключения, вам также потребуется пароль для текущего пользователя.
Я полагаю, что могу использовать что-то под названием Олицетворение, но я не уверен в лучших методах реализации этого или если это рекомендуемое решение.
За RunImpersonated
выполните следующие действия:
Настройте строку подключения с учетными данными Windows вместо имени пользователя и пароля.
services.AddDbContext<IISWindowsDbContext>(options =>options.UseSqlServer(@"Server=localhost\MSSQLSERVER01;Database=IISWindows;Trusted_Connection=True;"));
Useage
public IActionResult About() { IList<Blog> blogs = new List<Blog>(); var user = (WindowsIdentity)User.Identity; WindowsIdentity.RunImpersonated(user.AccessToken, () => { var impersonatedUser = WindowsIdentity.GetCurrent(); blogs = _context.Blogs.ToList(); }); return Ok(blogs); }