从非域计算机连接到域 SQL Server 2005
Posted
技术标签:
【中文标题】从非域计算机连接到域 SQL Server 2005【英文标题】:Connect to domain SQL Server 2005 from non-domain machine 【发布时间】:2010-05-12 20:17:14 【问题描述】:几天前我问了一个问题 (Access to SQL Server 2005 from a non-domain machine using Windows authentication),得到了一些有趣但不实用的建议。我想再次问这个问题,但要明确我的限制是什么:
我有一个 Windows 域,其中一台机器正在运行 SQL Server 2005,并且配置为仅支持 Windows 身份验证。我想在同一网络上的机器上运行 C# 客户端应用程序,但它不在域上,并访问 SQL Server 2005 实例上的数据库。
我无法在任何一台机器上创建或修改 OS 或 SQL Server 用户,也无法对权限或模拟进行任何更改,也无法使用 runas。
我知道我可以编写可以连接到 SQL Server 数据库的 Perl 和 Java 应用程序,只使用以下四个参数:服务器名称、数据库名称、用户名(以域\用户的形式)和密码。
在 C# 中,我尝试了各种方法:
string connectionString = "Data Source=server;Initial Catalog=database;User Id=domain\user;Password=password";
SqlConnection connection = new SqlConnection(connectionString);
connection.Open();
并尝试将集成安全设置为 true 和 false,但似乎没有任何效果。我想在 C# 中做的事情是不可能的吗?
感谢您的帮助,马丁
【问题讨论】:
【参考方案1】:我有一个类似的问题,我正在编写一个工具,该工具需要在一个域的机器上运行,并使用受信任的连接在另一个域的 SQL 服务器上进行身份验证。我能找到的关于这个主题的一切都表明它无法完成。相反,您必须加入域、使用 SQL 身份验证、参与一些名为 Kerberos 的小伙子,或者让您的网络人员建立信任关系,仅举几例。
问题是我知道我可以使用 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 命令使得调试应用程序变得非常困难,而且味道也不好。
最终我在the code project 上找到了这篇文章,它讨论了通过身份验证来操作 Active Directory,这是进行模拟的主要类:
使用系统; 使用 System.Runtime.InteropServices; // DLL导入 使用 System.Security.Principal; // WindowsImpersonationContext 命名空间 TestApp 类模仿者 // 组类型枚举 枚举 SECURITY_IMPERSONATION_LEVEL : int 安全匿名 = 0, 安全识别 = 1, 安全模拟 = 2, 安全委托 = 3 // 获取用户令牌 [DllImport("advapi32.dll", SetLastError = true)] 静态外部布尔登录用户(字符串 pszUsername,字符串 pszDomain,字符串 pszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken); // 关闭由 LogonUser 返回的张开的手 [DllImport("kernel32.dll", CharSet = CharSet.Auto)] extern static bool CloseHandle(IntPtr 句柄); // 创建重复的令牌句柄 [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] extern static bool DuplicateToken(IntPtr ExistingTokenHandle, int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle); WindowsImpersonationContext 新用户; /// /// 尝试模拟用户。如果成功,返回 /// 新用户身份的 WindowsImpersonationContext。 /// /// 要模拟的用户名 /// 登录域 /// 用户登录密码 /// public Impersonator(字符串 sUsername,字符串 sDomain,字符串 sPassword) // 初始化令牌 IntPtr pExistingTokenHandle = new IntPtr(0); IntPtr pDuplicateTokenHandle = new IntPtr(0); pExistingTokenHandle = IntPtr.Zero; pDuplicateTokenHandle = IntPtr.Zero; // 如果域名为空,则假定为本地机器 if (sDomain == "") sDomain = System.Environment.MachineName; 尝试 常量 int LOGON32_PROVIDER_DEFAULT = 0; // 创建令牌 // 常量 int LOGON32_LOGON_INTERACTIVE = 2; 常量 int LOGON32_LOGON_NEW_CREDENTIALS = 9; //const int SecurityImpersonation = 2; // 获取令牌句柄 bool bImpersonated = LogonUser(sUsername, sDomain, sPassword, LOGON32_LOGON_NEW_CREDENTIALS,LOGON32_PROVIDER_DEFAULT,参考 pExistingTokenHandle); // 模拟失败了吗? if (false == bImpersonated) int nErrorCode = Marshal.GetLastWin32Error(); // 显示 LogonUser 失败的原因 throw new ApplicationException("LogonUser() 失败,错误代码:" + nErrorCode); bool bRetVal = DuplicateToken(pExistingTokenHandle, (int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, ref pDuplicateTokenHandle); // DuplicateToken 失败了吗? 如果(假 == bRetVal) int nErrorCode = Marshal.GetLastWin32Error(); 关闭句柄(pExistingTokenHandle); // 关闭现有句柄 // 显示 DuplicateToken 失败的原因 throw new ApplicationException("DuplicateToken() 失败,错误代码:" + nErrorCode); 别的 // 使用新的主令牌创建新的身份 WindowsIdentity newId = new WindowsIdentity(pDuplicateTokenHandle); WindowsImpersonationContext impersonatedUser = newId.Impersonate(); 新用户 = 模拟用户; 最后 //关闭句柄 if (pExistingTokenHandle != IntPtr.Zero) 关闭句柄(pExistingTokenHandle); if (pDuplicateTokenHandle != IntPtr.Zero) 关闭句柄(pDuplicateTokenHandle); 公共无效撤消() 新用户.Undo();仅使用它:
Impersonator impersonator = new Impersonator("username", "domain", "password");
//Connect to and use SQL server
impersonator.Undo();
我在 Undo 方法中添加了否则模拟对象往往会被垃圾收集。我还更改了代码以使用 LOGON32_LOGON_NEW_CREDENTIALS ,但这是一个戳戳并运行以使其工作;我仍然需要完全了解它的作用,我感觉它与 runas 上的 /netonly 标志相同。我还要稍微分解一下构造函数。
【讨论】:
+1,很好的解决方案。关于垃圾回收问题:您可以将您的类重命名为ImpersonationContext
,继承IDisposable
并在Dispose
中执行Undo
的内容。因此,您的类可以按如下方式使用:using new ImpersonationContext(...) ...
。这也将确保您不会“忘记”撤消模拟。【参考方案2】:
在连接字符串中指定用户名和密码是没有用的,因为它们暗示了 SQL 身份验证,并且您已经指定 SQL Server 只接受 Windows 身份验证。
如果服务器不允许 SQL 身份验证,那么 唯一 的连接可能性是使用 Windows 身份验证,即。 IntegratedSecurity=true
。这意味着您的客户端将作为运行进程(或当前正在被模拟)的任何凭据进行身份验证。
为了使 Windows 身份验证起作用,您必须选择以下选项之一:
将未加入域的计算机加入到信任服务器域的域(可以是它自己的域!),然后将客户端进程作为域\用户凭据运行。 使用 NTLM 镜像帐户:客户端和服务器上具有相同名称和密码的一对本地用户。 以匿名方式授予对 SQL Server 的访问权限。如果您无法使客户端主机信任服务器域,也无法添加 NTLM 镜像帐户,并且 SQL Server 管理员足够清醒,不会启用 ANONYMOUS,那么您将无法连接。
【讨论】:
没有反对意见,但是:这个问题没有要求介绍 SQL Server 访问方法。它询问为什么 .net 框架无法使用 Windows 身份验证和替代凭据连接到 SQL Server尽管其他客户端技术(下面提到的 JDBC 驱动程序、Perl SQL Server 驱动程序、System.Data。 Windows CE 上的 SqlClient...) 允许你做这样的事情(所以它不能成为 SQL Server 的限制)。 @Heinzi Remus 确实提到了当前被模拟的凭据。司机可能就是这样做的。【参考方案3】:正如您所说的那样,Linux 机器上的 JDBC 或 Perl 都可以连接到 SQL Server使用 Windows 身份验证和不同于当前登录用户的凭据。 The same is true for Windows CE devices,顺便说一句。
我认为这不是 C# 的问题,而是 SQL Server OLE DB 驱动程序的问题。我猜上面提到的方法在网络级别“伪装成使用某些特定凭据的 Windows 机器”; SQL Server OLE DB 驱动程序缺少的一项功能。因此,我的建议是寻找可以访问 SQL Server 数据库的替代(可能是商业的?)OLE DB 驱动程序。不过,我不确定这样的事情是否存在。
【讨论】:
【参考方案4】:您必须configure SQL Server 才能允许 SQL Server 身份验证,即使用用户名和密码进行身份验证。
您不能通过域用户名/密码'like'服务器身份验证,即直接指定域用户名/密码。
我当然可能是错的,但我确信这不是 C# 或 .NET 的问题。如何在 Perl 或 Java 应用程序中登录 SQL Server??
【讨论】:
实际上,这个问题很清楚地表明,使用 SQL Server 身份验证不是一种选择(虽然没有反对意见......)【参考方案5】:我给你一个我比较熟悉的Java答案:我使用jTDS JDBC驱动和上面提到的四个参数。我不太了解的 Perl 应用程序,但它在 Linux 机器上运行,并且能够使用相同的参数进行连接。我无法更改 SQL Server 以支持 SQL 身份验证。
要回答 Remus 的建议,我不能做他建议的这三件事中的任何一件,但 Java 和 Perl 应用程序能够连接。还有其他想法吗?
谢谢,马丁
【讨论】:
【参考方案6】:可以选择prompt for credentials吗?
【讨论】:
不——至少我认为你的意思是这样。连接凭据在 C# 应用程序启动时读取的配置文件中指定。【参考方案7】:这是我使用 jTDS JDBC 驱动程序从非域机器连接的示例代码:
Class.forName("net.sourceforge.jtds.jdbc.Driver").newInstance(); 字符串 url = "jdbc:jtds:sqlserver://server/database;domain=domain"; conn = DriverManager.getConnection(url, "user", "password");
【讨论】:
您应该将这些内容添加到您的问题中(使用问题下方的“编辑”按钮),而不是将其添加为答案。以上是关于从非域计算机连接到域 SQL Server 2005的主要内容,如果未能解决你的问题,请参考以下文章
非域环境下SQL Server搭建Mirror(镜像)的详细步骤
使用域用户(AD 用户)连接到没有密码的 SQL Server