如何解决在Linux(Ubuntu 18.04)中使用EF Core数据库脚手架时出现的“无法使用Kerberos进行身份验证”问题?是否有任何解决方案?

15
我一直在尝试使用EntityFrameworkCore开发一个简单的AspNetCore应用程序,以连接和操作MSSQL服务器数据库。并通过Rider IDE、数据库客户端工具(DBeaver)和dotnet命令行接口(dotnet ef)来管理所有这些。我使用的是数据库优先的方法(在MSSQL服务器上创建数据库,填充表格,然后基于表格构建模型)。
我的逐步操作如下:
1)在我的Ubuntu 18.04上安装和设置MSSQL服务器。安装命令行工具"SQLCMD"。/// 指南链接 - https://learn.microsoft.com/en-gb/sql/linux/quickstart-install-connect-ubuntu?view=sql-server-ver15 2)本地连接到我的MSSQL服务器实例。 sqlcmd -S localhost -U SA -P 'MyPasswd' 3)使用Transact-SQL创建了一个数据库,并安装了一个DB客户端工具(DBeaver),以便快速管理我的数据库现在和将来。
下一步,正如我所想的那样,是使用关于将我的Web应用程序连接到数据库的教程。这些教程可以在这里找到:https://blog.jetbrains.com/dotnet/2017/08/09/running-entity-framework-core-commands-rider/https://www.entityframeworktutorial.net/efcore/create-model-for-existing-database-in-ef-core.aspx
我的ASP.NET Core项目的包引用如下:
  • Microsoft.EntityFrameworkCore
  • Microsoft.EntityFrameworkCore.SqlServer
  • Microsoft.EntityFrameworkCore.Tools
在输入CLI命令dotnet ef dbcontext scaffold "Server=localhost;Database=WebAppDB;Integrated Security=true;" Microsoft.EntityFrameworkCore.SqlServer -c RsvpContext(用于构建"RsvpContext"上下文以连接到我的数据库WebAppDB)之后,
我看到了我所看到的:
Build started...
Build succeeded.
Microsoft.Data.SqlClient.SqlException (0x80131904): **Cannot authenticate using 
Kerberos. Ensure Kerberos has been initialized on the client with 'kinit' and a 
Service Principal Name has been registered for the SQL Server to allow Kerberos 
authentication.**

ErrorCode=InternalError, Exception=Interop+NetSecurityNative+GssApiException: 
GSSAPI operation failed with error - Unspecified GSS failure.  Minor code may 
provide more information (SPNEGO cannot find mechanisms to negotiate).


   at System.Net.Security.NegotiateStreamPal.GssInitSecurityContext(SafeGssContextHandle& context, SafeGssCredHandle credential, Boolean isNtlm, SafeGssNameHandle targetName, GssFlags inFlags, Byte[] buffer, Byte[]& outputBuffer, UInt32& outFlags, Int32& isNtlmUsed)

   at System.Net.Security.NegotiateStreamPal.EstablishSecurityContext(SafeFreeNegoCredentials credential, SafeDeleteContext& context, String targetName, ContextFlagsPal inFlags, SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, ContextFlagsPal& outFlags)

   at Microsoft.Data.SqlClient.SNI.SNIProxy.GenSspiClientContext(SspiClientContextStatus sspiClientContextStatus, Byte[] receivedBuff, Byte[]& sendBuff, Byte[] serverName)

   at Microsoft.Data.SqlClient.SNI.TdsParserStateObjectManaged.GenerateSspiClientContext(Byte[] receivedBuff, UInt32 receivedLength, Byte[]& sendBuff, UInt32& sendLength, Byte[] _sniSpnBuffer)

   at Microsoft.Data.SqlClient.TdsParser.SNISSPIData(Byte[] receivedBuff, UInt32 receivedLength, Byte[]& sendBuff, UInt32& sendLength)

   at Microsoft.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, SqlCredential credential, Object providerInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString userConnectionOptions, SessionData reconnectSessionData, Boolean applyTransientFaultHandling, String accessToken, DbConnectionPool pool, SqlAuthenticationProviderManager sqlAuthProviderManager)

   at Microsoft.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions)

   at Microsoft.Data.ProviderBase.DbConnectionFactory.CreatePooledConnection(DbConnectionPool pool, DbConnection owningObject, DbConnectionOptions options, DbConnectionPoolKey poolKey, DbConnectionOptions userOptions)

   at Microsoft.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)

   at Microsoft.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)

   at Microsoft.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
   
   at Microsoft.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection)
   
at Microsoft.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection)

   at Microsoft.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)

   at Microsoft.Data.ProviderBase.DbConnectionClosed.TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)

   at Microsoft.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry)

   at Microsoft.Data.SqlClient.SqlConnection.Open()

   at Microsoft.EntityFrameworkCore.SqlServer.Scaffolding.Internal.SqlServerDatabaseModelFactory.Create(DbConnection connection, DatabaseModelFactoryOptions options)
   
at Microsoft.EntityFrameworkCore.SqlServer.Scaffolding.Internal.SqlServerDatabaseModelFactory.Create(String connectionString, DatabaseModelFactoryOptions options)

   at Microsoft.EntityFrameworkCore.Scaffolding.Internal.ReverseEngineerScaffolder.ScaffoldModel(String connectionString, DatabaseModelFactoryOptions databaseOptions, ModelReverseEngineerOptions modelOptions, ModelCodeGenerationOptions codeOptions)

   at Microsoft.EntityFrameworkCore.Design.Internal.DatabaseOperations.ScaffoldContext(String provider, String connectionString, String outputDir, String outputContextDir, String dbContextClassName, IEnumerable`1 schemas, IEnumerable`1 tables, Boolean useDataAnnotations, Boolean overwriteFiles, Boolean useDatabaseNames)

   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.ScaffoldContextImpl(String provider, String connectionString, String outputDir, String outputDbContextDir, String dbContextClassName, IEnumerable`1 schemaFilters, IEnumerable`1 tableFilters, Boolean useDataAnnotations, Boolean overwriteFiles, Boolean useDatabaseNames)

   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.ScaffoldContext.<>c__DisplayClass0_0.<.ctor>b__0()

   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()

   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
ClientConnectionId:38f805bc-5879-458b-9256-d6a201d7ce99
Cannot authenticate using Kerberos. Ensure Kerberos has been initialized on the 
client with 'kinit' and a Service Principal Name has been registered for the SQL 
Server to allow Kerberos authentication.
ErrorCode=InternalError, Exception=Interop+NetSecurityNative+GssApiException: 
GSSAPI operation failed with error - Unspecified GSS failure.  Minor code may 
provide more information (SPNEGO cannot find mechanisms to negotiate).

   at System.Net.Security.NegotiateStreamPal.GssInitSecurityContext(SafeGssContextHandle& context, SafeGssCredHandle credential, Boolean isNtlm, SafeGssNameHandle targetName, GssFlags inFlags, Byte[] buffer, Byte[]& outputBuffer, UInt32& outFlags, Int32& isNtlmUsed)

   at System.Net.Security.NegotiateStreamPal.EstablishSecurityContext(SafeFreeNegoCredentials credential, SafeDeleteContext& context, String targetName, ContextFlagsPal inFlags, SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, ContextFlagsPal& outFlags)

   at Microsoft.Data.SqlClient.SNI.SNIProxy.GenSspiClientContext(SspiClientContextStatus sspiClientContextStatus, Byte[] receivedBuff, Byte[]& sendBuff, Byte[] serverName)

   at Microsoft.Data.SqlClient.SNI.TdsParserStateObjectManaged.GenerateSspiClientContext(Byte[] receivedBuff, UInt32 receivedLength, Byte[]& sendBuff, UInt32& sendLength, Byte[] _sniSpnBuffer)

   at Microsoft.Data.SqlClient.TdsParser.SNISSPIData(Byte[] receivedBuff, UInt32 receivedLength, Byte[]& sendBuff, UInt32& sendLength)

如果有人,最好是在Linux上工作,遇到了同样的问题,请告诉我并分享你的解决方案(在这种情况下该怎么做的指南)。

在Linux服务器上配置Kerberos是一项漫长而不简单的任务。简单的答案是在此处使用SQL身份验证。除非您非常熟悉Linux和SQL Server,否则我不建议尝试进入Kerberos路线。 - Thom A
最好在Linux上工作。Windows使用Kerberos进行Windows身份验证,当加入域、启动机器等时,操作系统会自动执行配置。但是在Linux上不是这样的。您没有在问题中发布任何Kerberos配置步骤。该机器是否属于AD域?Kerberos是否以其他方式配置? - Panagiotis Kanavos
请确保在客户端上使用“kinit”初始化了Kerberos,并为SQL Server注册了服务主体名称,以允许Kerberos身份验证。您已经完成了这个步骤吗? - Panagiotis Kanavos
对于Linux系统,我是否应该像这里https://www.howtoforge.com/tutorial/how-to-setup-kerberos-server-and-client-on-ubuntu-1804-lts/中所述安装和配置Kerberos客户端和服务器呢?因为这篇文章是针对Windows的。 - paulokunev
@PanagiotisKanavos,您能解释一下如何使用SQL身份验证吗?我想试试。 - paulokunev
显示剩余3条评论
2个回答

31

当我从本地部署转移到Azure Kubernetes (AKS集群)云解决方案时,我遇到了这个问题。

简短的答案是:它与集成身份验证有关。

更详细的回答是:原因是在使用像我们之前所用的本地解决方案一样的Windows操作系统时,它可以支持集成身份验证,但是当在Kubernetes中以独立方式、虚拟机、Docker或容器解决方案等托管Linux操作系统时,就无法进行集成身份验证。

我将集成安全性更改为false,使得集成身份验证类似于 (integrated security=false;),并且在连接字符串中提供了具有数据库适当访问权限的用户名和密码 (User ID=YourProperUserName;Password=YourProperUserPassword;)。

问题已解决。

此外:

  • @Ismail Umar 在评论中提到要删除 Trusted_Connection=True
  • @alexDuty 在评论中提到要添加 TrustServerCertificate=True

我个人没有遇到评论中提到的问题,但提供这些信息是为了帮助有需要的人。


6
除了上面的回答之外,如果你在连接字符串中有"Trusted_Connection=True",请将其删除。 - Ismail Umar
3
另外再加一点可能对其他人有用的信息:应用Integrated security=FalseTrustServerCertificate=True两者都可以解决我的问题。 - alexDuty

0

我尝试了移除 Trusted_Connection=True 并添加 TrustServerCertificate=True,这样就可以在托管在 Docker 容器中的 SQL Server 上运行 EF 迁移。

连接字符串:

Server=127.0.0.1,1433;Database=AuthDb;Integrated security=False;User=sa;Password=password;TrustServerCertificate=True;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接