Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从非域计算机连接到域SQL Server 2005_C#_.net_Sql Server_Active Directory_Sql Authentication - Fatal编程技术网

C# 从非域计算机连接到域SQL Server 2005

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应用程序,它

几天前我问了一个问题(),得到了一些有趣但不实用的建议。我想再问一次这个问题,但要明确我的限制是什么:

我有一个Windows域,其中一台计算机正在运行SQL Server 2005,并且配置为仅支持Windows身份验证。我希望在同一网络上但不在域上的计算机上运行C#客户端应用程序,并访问SQL Server 2005实例上的数据库

我无法在这两台计算机上创建或修改OS或SQL Server用户,无法对权限或模拟进行任何更改,也无法使用runas

我知道我可以编写Perl和Java应用程序,它们可以只使用以下四个参数连接到SQL Server数据库:服务器名称、数据库名称、用户名(格式为domain\user)和密码

在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#中根本不可能吗

感谢您的帮助,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();