C# 从非域计算机连接到域SQL Server 2005
几天前我问了一个问题(),得到了一些有趣但不实用的建议。我想再问一次这个问题,但要明确我的限制是什么: 我有一个Windows域,其中一台计算机正在运行SQL Server 2005,并且配置为仅支持Windows身份验证。我希望在同一网络上但不在域上的计算机上运行C#客户端应用程序,并访问SQL Server 2005实例上的数据库 我无法在这两台计算机上创建或修改OS或SQL Server用户,无法对权限或模拟进行任何更改,也无法使用runas 我知道我可以编写Perl和Java应用程序,它们可以只使用以下四个参数连接到SQL Server数据库:服务器名称、数据库名称、用户名(格式为domain\user)和密码 在C#中,我尝试了各种方法:C# 从非域计算机连接到域SQL Server 2005,c#,.net,sql-server,active-directory,sql-authentication,C#,.net,Sql Server,Active Directory,Sql Authentication,几天前我问了一个问题(),得到了一些有趣但不实用的建议。我想再问一次这个问题,但要明确我的限制是什么: 我有一个Windows域,其中一台计算机正在运行SQL Server 2005,并且配置为仅支持Windows身份验证。我希望在同一网络上但不在域上的计算机上运行C#客户端应用程序,并访问SQL Server 2005实例上的数据库 我无法在这两台计算机上创建或修改OS或SQL Server用户,无法对权限或模拟进行任何更改,也无法使用runas 我知道我可以编写Perl和Java应用程序,它
string connectionString = "Data Source=server;Initial Catalog=database;User Id=domain\user;Password=password";
SqlConnection connection = new SqlConnection(connectionString);
connection.Open();
并尝试将集成安全设置为true和false,但似乎没有任何效果。我想做的事在C#中根本不可能吗
感谢您的帮助,Martin您必须允许SQL Server身份验证,即使用用户名和密码进行身份验证
您不能通过域用户名/密码“像”服务器身份验证进行身份验证,即直接指定域用户名/密码
我当然可能错了,但我确信这不是C#或.NET的问题。如何在Perl或Java应用程序中登录SQL Server???在连接字符串中指定用户名和密码是无用的,因为这意味着SQL身份验证,并且您已经指定SQL Server只接受Windows身份验证 如果服务器不允许SQL身份验证,则连接的唯一可能性是使用Windows身份验证,即
IntegratedSecurity=true
。这意味着您的客户端将作为运行进程(或当前正在模拟的)的任何凭据进行身份验证
要使Windows身份验证正常工作,您必须选择以下选项之一:
- 将未加入域的计算机加入信任服务器域的域(它可以是自己的域!),然后作为域\用户凭据运行客户端进程李>
- 使用NTLM镜像帐户:客户端和服务器上具有相同名称和密码的一对本地用户
- 授予对SQL Server的匿名访问权限
如果您无法使客户机主机信任服务器域,也无法添加NTLM镜像帐户,并且SQL server管理员足够健全,无法启用匿名,那么您将无法连接。我将给您一个我更熟悉的Java答案:我使用具有上述四个参数的jTDS JDBC驱动程序。我不太了解Perl应用程序,但它运行在Linux机器上,并且能够使用相同的参数进行连接。我无法更改SQL Server以支持SQL身份验证 为了回答Remus的建议,我不能做他建议的三件事中的任何一件,但是Java和Perl应用程序能够连接起来。还有其他想法吗
谢谢,Martin,这是一个选项吗?以下是我使用jTDS JDBC驱动程序从非域计算机连接的示例代码: Class.forName(“net.sourceforge.jtds.jdbc.Driver”).newInstance(); String url=“jdbc:jtds:sqlserver://server/database;域=域”;
conn=DriverManager.getConnection(url,“用户”,“密码”) 正如您所说,Linux机器上的JDBC或Perl都可以使用Windows身份验证和与当前登录用户不同的凭据连接到SQL Server,顺便说一下
我认为这不是C#的问题,而是SQL Server OLE DB驱动程序的问题。我猜上面提到的方法在网络级别上“使用某些特定凭据假装是Windows机器”;SQL Server OLE DB驱动程序缺少的功能。因此,我的建议是寻找可以访问SQL Server数据库的替代(可能是商业的)OLE DB驱动程序。不过,我不确定是否存在这种情况。我在编写一个工具时遇到了类似的问题,该工具需要在一个域上的计算机上运行,并使用可信连接在另一个域上的SQL server上进行身份验证。我所能找到的关于这个问题的一切都表明这是不可能的。相反,您必须加入域,使用SQL身份验证,参与称为Kerberos的chap,或者让您的网络人员建立信任关系,举几个备选方案 问题是,我知道我可以使用RUNAS以某种方式让它工作,因为我已经用SSMS证明了这一点:
C:\WINDOWS\system32\runas.exe /netonly /savecred /user:megacorp\joe.bloggs "C:\Program Files\Microsoft SQL Server\90\Tools\Binn\VSShell\Common7\IDE\SqlWb.exe"
/netonly标志允许我使用本地凭据执行exe,并使用远程凭据访问网络,我想,无论如何,我从远程服务器获得了预期的结果集。问题是runas命令使调试应用程序变得非常困难,而且它的味道也不好
最终我找到了这篇文章,其中讨论了如何通过身份验证来操作Active Directory,下面是进行模拟的主要类:
using System;
using System.Runtime.InteropServices; // DllImport
using System.Security.Principal; // WindowsImpersonationContext
namespace TestApp
{
class Impersonator
{
// group type enum
enum SECURITY_IMPERSONATION_LEVEL : int
{
SecurityAnonymous = 0,
SecurityIdentification = 1,
SecurityImpersonation = 2,
SecurityDelegation = 3
}
// obtains user token
[DllImport("advapi32.dll", SetLastError = true)]
static extern bool LogonUser(string pszUsername, string pszDomain, string pszPassword,
int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
// closes open handes returned by LogonUser
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
extern static bool CloseHandle(IntPtr handle);
// creates duplicate token handle
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
extern static bool DuplicateToken(IntPtr ExistingTokenHandle,
int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);
WindowsImpersonationContext newUser;
///
/// Attempts to impersonate a user. If successful, returns
/// a WindowsImpersonationContext of the new users identity.
///
/// Username you want to impersonate
/// Logon domain
/// User's password to logon with
///
public Impersonator(string sUsername, string sDomain, string sPassword)
{
// initialize tokens
IntPtr pExistingTokenHandle = new IntPtr(0);
IntPtr pDuplicateTokenHandle = new IntPtr(0);
pExistingTokenHandle = IntPtr.Zero;
pDuplicateTokenHandle = IntPtr.Zero;
// if domain name was blank, assume local machine
if (sDomain == "")
sDomain = System.Environment.MachineName;
try
{
const int LOGON32_PROVIDER_DEFAULT = 0;
// create token
// const int LOGON32_LOGON_INTERACTIVE = 2;
const int LOGON32_LOGON_NEW_CREDENTIALS = 9;
//const int SecurityImpersonation = 2;
// get handle to token
bool bImpersonated = LogonUser(sUsername, sDomain, sPassword,
LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_DEFAULT, ref pExistingTokenHandle);
// did impersonation fail?
if (false == bImpersonated)
{
int nErrorCode = Marshal.GetLastWin32Error();
// show the reason why LogonUser failed
throw new ApplicationException("LogonUser() failed with error code: " + nErrorCode);
}
bool bRetVal = DuplicateToken(pExistingTokenHandle, (int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, ref pDuplicateTokenHandle);
// did DuplicateToken fail?
if (false == bRetVal)
{
int nErrorCode = Marshal.GetLastWin32Error();
CloseHandle(pExistingTokenHandle); // close existing handle
// show the reason why DuplicateToken failed
throw new ApplicationException("DuplicateToken() failed with error code: " + nErrorCode);
}
else
{
// create new identity using new primary token
WindowsIdentity newId = new WindowsIdentity(pDuplicateTokenHandle);
WindowsImpersonationContext impersonatedUser = newId.Impersonate();
newUser = impersonatedUser;
}
}
finally
{
// close handle(s)
if (pExistingTokenHandle != IntPtr.Zero)
CloseHandle(pExistingTokenHandle);
if (pDuplicateTokenHandle != IntPtr.Zero)
CloseHandle(pDuplicateTokenHandle);
}
}
public void Undo()
{
newUser.Undo();
}
}
}
我添加了Undo方法,否则模拟对象会被垃圾回收。我还修改了代码,使用LOGON32\u LOGON\u NEW\u凭据,但这是一个戳和运行,使其工作;我仍然需要完全理解它的功能,我感觉它与runas上的/netonly标志相同。我还将对构造函数进行一些分解。否-至少按照我认为你的意思。连接凭据在C#应用程序启动时读取的配置文件中指定。您应该将这些内容添加到问题中(使用问题下方的“编辑”按钮),而不是将其添加为答案。事实上,该问题非常清楚地表明,使用SQL Server身份验证不是一个选项(无否决权,第
Impersonator impersonator = new Impersonator("username", "domain", "password");
//Connect to and use SQL server
impersonator.Undo();