使用Dynamics GP用户名和密码的SqlConnection-用户登录失败

时间:2018-07-17 09:36:58

标签: c# sql sql-server microsoft-dynamics

我正在为Dynamics GP编写加载项,并且尝试运行自定义存储过程,但是当我尝试打开连接时,收到一条错误消息,提示“用户登录失败:”。

如果我手动使用系统管理员的用户名和密码,则所有操作都会正确执行。但是,我想使用登录Dynamics GP的用户名和密码。

string gpUsername = Dynamics.Globals.UserId.Value;
string gpPassword = Dynamics.Globals.SqlPassword.Value;
string companyDb = Dynamics.Globals.IntercompanyId.Value;
string dataSource = "sql-server-name";

SqlConnectionStringBuilder constringBuilder = new SqlConnectionStringBuilder();
constringBuilder.UserID = gpUsername;
constringBuilder.Password = gpPassword;
constringBuilder.InitialCatalog = companyDb;
constringBuilder.DataSource = dataSource;
constringBuilder.WorkstationID = Environment.MachineName;
constringBuilder.MultipleActiveResultSets = true;
constringBuilder.ApplicationName = $"{FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).ProductName} (GP)";
constringBuilder.IntegratedSecurity = false;
string constring = constringBuilder.ConnectionString;
SqlConnection con = new SqlConnection(constring);
con.Open();

这是完整的堆栈跟踪:

Dynamics.exe Warning: 0 : Exception occurred while updating Item class 1255. Review the error message below.
    System.Data.SqlClient.SqlException (0x80131904): Login failed for user '<username>'.
   at System.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, SqlCredential credential, Object providerInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString userConnectionOptions, SessionData reconnectSessionData, DbConnectionPool pool, String accessToken, Boolean applyTransientFaultHandling, SqlAuthenticationProviderManager sqlAuthProviderManager)
   at System.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions)
   at System.Data.ProviderBase.DbConnectionFactory.CreatePooledConnection(DbConnectionPool pool, DbConnection owningObject, DbConnectionOptions options, DbConnectionPoolKey poolKey, DbConnectionOptions userOptions)
   at System.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
   at System.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
   at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
   at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection)
   at System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection)
   at System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
   at System.Data.ProviderBase.DbConnectionClosed.TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
   at System.Data.SqlClient.SqlConnection.TryOpenInner(TaskCompletionSource`1 retry)
   at System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry)
   at System.Data.SqlClient.SqlConnection.Open()
   at Dyn2Bib.GPAddIn.ProcessTransaction(String srs, String srsName, String changeType)
ClientConnectionId:1a4c93c1-0efd-4590-8c9f-98265eaafaa2
Error Number:18456,State:1,Class:14

如果我将DataSource中的constringBuilder更改为使用Dynamics.Globals.SqlDataSourceName.Value,则似乎根本找不到网络上的数据源并给出错误:

Dynamics.exe Warning: 0 : Exception occurred while updating Item class 1255. Review the error message below.
    System.Data.SqlClient.SqlException (0x80131904): 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: Named Pipes Provider, error: 40 - Could not open a connection to SQL Server) ---> System.ComponentModel.Win32Exception (0x80004005): The network path was not found
   at System.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, SqlCredential credential, Object providerInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString userConnectionOptions, SessionData reconnectSessionData, DbConnectionPool pool, String accessToken, Boolean applyTransientFaultHandling, SqlAuthenticationProviderManager sqlAuthProviderManager)
   at System.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions)
   at System.Data.ProviderBase.DbConnectionFactory.CreatePooledConnection(DbConnectionPool pool, DbConnection owningObject, DbConnectionOptions options, DbConnectionPoolKey poolKey, DbConnectionOptions userOptions)
   at System.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
   at System.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
   at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
   at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection)
   at System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection)
   at System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
   at System.Data.ProviderBase.DbConnectionClosed.TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
   at System.Data.SqlClient.SqlConnection.TryOpenInner(TaskCompletionSource`1 retry)
   at System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry)
   at System.Data.SqlClient.SqlConnection.Open()
   at Dyn2Bib.GPAddIn.ProcessTransaction(String srs, String srsName, String changeType)
ClientConnectionId:00000000-0000-0000-0000-000000000000
Error Number:53,State:0,Class:20

如果我将连接字符串打印到屏幕上,则它看起来是正确的,并且正如我所提到的,如果我手动使用系统管理员帐户,它会起作用。

我可以使用Dynamics GP帐户直接连接到SQL Server吗?服务器上有一个相应的登录名,因此似乎应该已经正确配置了它。有人知道我在做什么错吗?我是否需要对Dynamics GP帐户进行任何更改以允许其使用SQL身份验证进行连接?

3 个答案:

答案 0 :(得分:1)

我假设登录到Dynamics GP的人的用户名和密码仅是Dynamics GP应用程序用户,而不是实际的数据库用户。

您可以通过将身份验证改为Windows身份验证来解决此问题

这是通过以下方式实现的:

  1. 创建Windows组
  2. 为每个应能够运行您的自定义SP的Windows用户填充该Windows组
  3. 使用SQL Server Management Studio,将此窗口组添加为SQL Server登录名
  4. 在您的代码中,

删除这些行:

constringBuilder.UserID = gpUsername;
constringBuilder.Password = gpPassword;

并像这样更改此行:

 constringBuilder.IntegratedSecurity = true;

这意味着将使用其Windows凭据而不是(无效的)SQL凭据建立连接

这些Windows凭据先前已通过完成步骤1-3授予服务器登录访问权限

这还不是故事的结局。现在,您需要启用该组,使其公正有权访问您的SP

  1. 使用存储过程在数据库中创建数据库角色
  2. 授予该角色执行对自定义SP的访问权限
  3. 最后,要将其链接起来,请编辑您在步骤3中创建的登录名,授予它对数据库的访问权限,并将其添加到在步骤5中创建的角色中。

复杂吗?是。但是,授予用户访问数据库的权限非常重要。这样

  • 用户可以登录并运行SP,仅此而已。
  • 要授予和删除用户,请在Windows组中添加或删除用户(如果需要,可以重复使用现有的GP Windows组)
  • 如果创建其他需要访问的数据库对象,则授予数据库角色对其的访问权限

如果此解决方案对您有吸引力,那么我可以根据您的需要进行扩展。

答案 1 :(得分:1)

方法是使用GP中的连接对象

using Dex = Microsoft.Dexterity.Applications;

        internal static SqlConnection conn = new SqlConnection();

        internal static SqlConnection GetOpenGPConnection()
        {
            try
            {
		//Call Startup
		int resp = GPConnection.Startup();

		// Create the connection object
		Microsoft.Dexterity.GPConnection GPConn = new GPConnection();

		//  Initialize
		GPConn.Init("MyVSTDCompanyid", "myVSTDGPAuthCode");  // get this from Microsoft GP Dev Tools Support
		conn.ConnectionString = String.Format("Database = {0}", Dex.Dynamics.Globals.IntercompanyId.Value);

		GPConn.Connect(conn, Dex.Dynamics.Globals.SqlDataSourceName, Dex.Dynamics.Globals.UserId, Dex.Dynamics.Globals.SqlPassword);

		if ((GPConn.ReturnCode & (int)GPConnection.ReturnCodeFlags.SuccessfulLogin) == (int)GPConnection.ReturnCodeFlags.SuccessfulLogin)
		{
		return conn;
		}
		else
		{//...  user authenticaltion failed - backup plan?  fallback to windows auth?  
		return null
		}
	
            }
            catch (Exception ex)
            {
            	// your catch handling mechanism
            }
        }

答案 2 :(得分:0)

GP使用SQL身份验证。 GP用户是SQL登录名。 (您可以将Windows Auth与GP一起使用FastPath。FastPath越来越流行,MS也一直在谈论其对本机的支持)

尽管用户具有SQL登录名,但是应用程序在SQL上创建帐户并哈希密码。这是为了防止用户使用Crystal等查询无法访问的数据

相关问题