简体   繁体   English

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

[英]SqlConnection using Dynamics GP username and password — Login failed for user

I am writing an add-in for Dynamics GP and I'm attempting to run a custom stored procedure, but when I try to open the connection I get an error message saying "Login failed for user: ". 我在为Dynamics GP编写加载项,并尝试运行自定义存储过程,但是当我尝试打开连接时,出现一条错误消息,提示“用户登录失败:”。

If I manually use the system administrator username and password, everything executes correctly. 如果我手动使用系统管理员的用户名和密码,那么一切都会正常执行。 However, I'd like to use the username and password of the person logging into the 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();

This is the full stack trace: 这是完整的堆栈跟踪:

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

If I change the DataSource in constringBuilder to use Dynamics.Globals.SqlDataSourceName.Value , it looks like it can't find the data source on the network at all and gives the error: 如果我改变了DataSourceconstringBuilder使用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

If I print the connection string to the screen, it looks correct and as I mentioned, if I manually use the system administrator account it works. 如果我将连接字符串打印到屏幕上,它看起来是正确的,并且正如我所提到的,如果我手动使用系统管理员帐户,它将起作用。

It would make sense to me that I'd be able to connect directly to the SQL server with the Dynamics GP account? 我可以使用Dynamics GP帐户直接连接到SQL Server吗? There is a corresponding login on the server, so it seems like this should be configured correctly already. 服务器上有一个相应的登录名,因此似乎应该已经正确配置了它。 Does anyone know what I'm doing wrong here? 有人知道我在做什么错吗? Do I need to make any changes to the Dynamics GP account to allow it to connect using SQL authentication? 我是否需要对Dynamics GP帐户进行任何更改以允许其使用SQL身份验证进行连接?

I assume the username and password of the person logging into the Dynamics GP is a dynamics GP application user only, not an actual database user. 我假设登录Dynamics GP的人的用户名和密码仅是Dynamics GP应用程序用户,而不是实际的数据库用户。

You could solve this by changing your authentication to windows authentication instead 您可以通过将身份验证更改为Windows身份验证来解决此问题

This is achieved as follows: 这可以通过以下方式实现:

  1. Create a windows group 创建一个Windows组
  2. Populate this windows group with every windows user who should be able to run your custom SP 使用应该能够运行自定义SP的每个Windows用户填充该Windows组
  3. Using SQL Server Management Studio, Add this windows group as a SQL Server login 使用SQL Server Management Studio,将此窗口组添加为SQL Server登录名
  4. In your code, 在您的代码中

Remove these lines: 删除这些行:

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

and change this line like so: 并像这样更改此行:

 constringBuilder.IntegratedSecurity = true;

This means the connection will be made using their windows credentials, not using (invalid) SQL credentials 这意味着将使用其Windows凭据而不是(无效)SQL凭据建立连接

These windows credentials have previously been granted server login access by completing steps 1-3 通过完成步骤1-3,这些Windows凭据先前已被授予服务器登录访问权限

That's not the end of the story. 这还不是故事的结局。 Now you need to enable the group to just have access to your SP 现在,您需要启用组刚刚访问您的SP

  1. Create a database role in the database with the stored procedure 使用存储过程在数据库中创建数据库角色
  2. Grant this role execute access to your custom SP 授予该角色执行对自定义SP的访问权限
  3. Lastly, to link it all up, edit the login you created at step 3, grant it access to the database and add it to the role you created in step 5 最后,要将其链接起来,请编辑您在步骤3中创建的登录名,授予它对数据库的访问权限,并将其添加到在步骤5中创建的角色中

Complicated? 复杂? Yes. 是。 But granting user access to a database is a very big deal. 但是,授予用户访问数据库的权限非常重要。 This way 这条路

  • The users can login and run the SP and nothing else. 用户可以登录并运行SP,而无其他操作。
  • To grant and remove users you add or remove them from the windows group (You could reuse a preexisting GP windows group if you wish) 要授予和删除用户,可以在windows组中添加或删除用户(如果需要,可以重复使用现有的GP windows组)
  • If you create other DB objects that they need access to, you grant the database role access to them 如果创建需要访问的其他数据库对象,则授予数据库角色访问权限

If this solution appeals to you, I can expand on it if you wish. 如果您希望使用此解决方案,我可以在其上进行扩展。

the way to do it is to use the connection object from GP 做到这一点的方法是使用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 } } 

GP uses SQL Authentication. GP使用SQL身份验证。 GP users are SQL Logins. GP用户是SQL登录名。 (You can use Windows Auth with GP using FastPath. increasingly popular, and MS has been talking of native support for it too) (您可以将Windows Auth与使用FastPath的GP一起使用。越来越流行,MS也一直在谈论其对本机的支持)

Although the user has a SQL login, the application creates the account on SQL and hashes the password. 尽管用户具有SQL登录名,但是应用程序在SQL上创建帐户并哈希密码。 this is to prevent the user from using something like Crystal to query data that they don't have access to 这是为了防止用户使用诸​​如Crystal之类的工具来查询他们无权访问的数据

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 SQLConnection错误“用户登录失败” C# - error “Login failed for user” C# with SQLConnection “使用SQLConnection对用户”C#登录失败 - “Login failed for user” C# with SQLConnection 用户“用户名”的登录失败 - Login failed for user 'username' 尝试在C#中打开()SqlConnection时用户登录失败 - Login Failed for User when trying to Open() a SqlConnection in C# SQLConnection连接错误“用户服务器/来宾登录失败” - SQLConnection connection error “Login failed for user server/guest” 由于用户不存在/密码/用户名正确而导致尝试登录网站失败时如何返回消息? - How to return a message when a try to login to the website failed, because the user does not exist/password/username arent correct? SQL异常 - 用户“UserName $”登录失败 - SQL Exception - Login failed for user “UserName$” 通过Facebook登录名注册用户(未指定用户名/密码) - Register a user via Facebook login (no username/password specified) 无法打开登录请求的数据库“ dbname”。 登录失败。 用户“ machinname \\ username”的登录失败 - Cannot open database “dbname” requested by the login. The login failed. Login failed for user “machinname\username” 如何修复“用户&#39;Username.sql&#39;登录失败。”? - How do I fix “Login failed for user 'Username.sql'.”?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM