使用 pyodbc 从 Linux 向 Windows SQL Server 进行身份验证

Posted

技术标签:

【中文标题】使用 pyodbc 从 Linux 向 Windows SQL Server 进行身份验证【英文标题】:Authenticate from Linux to Windows SQL Server with pyodbc 【发布时间】:2018-09-16 16:05:57 【问题描述】:

我正在尝试使用 pyodbc 从 linux 机器连接到 windows SQL Server。

我确实有一些限制:

需要使用 windows 域帐户登录 需要使用python3 需要从 Linux 到 Windows 来做 需要连接到特定实例

我按照 microsoft 的描述设置了环境并让它工作(我可以导入 pyodbc 并使用配置的 mussel 驱动程序)。

我不熟悉 Windows 域身份验证等等,所以这就是我的问题所在。

我的连接字符串:

DRIVER=ODBC Driver 17 for SQL Server;SERVER=myserver.mydomain.com;PORT=1433;DATABASE=MyDatabase;Domain=MyCompanyDomain;Instance=MyInstance;UID=myDomainUser;PWD=XXXXXXXX;Trusted_Connection=yes;Integrated_Security=SSPI

假设应该使用“Trusted_Connection”来使用 Windows 域身份验证,而不是直接使用 SQL 服务器进行身份验证。

运行时出现的错误pyodbc.connect(connString)

pyodbc.Error: ('HY000', '[HY000] [unixODBC][Microsoft][ODBC Driver 17 for SQL Server]SSPI Provider: No Kerberos credentials available (851968) (SQLDriverConnect)')

从我读到的其他来源,这应该可以在 Windows 上运行,因为此代码将使用当前登录用户的凭据。

我的问题是如何使用 Windows 域凭据从 Linux 连接到 Windows SQL Server 实例。

【问题讨论】:

我相当肯定微软的 Linux ODBC 驱动程序 (msodbcsql) 只支持使用 Windows 凭据连接到 SQL Server 实例的 Kerberos。如果您没有适当的 Kerberos 设置,那么您可以改用 FreeTDS ODBC,因为它能够使用旧的 NTLMv2 协议(如果 SQL Server 接受它)。 谢谢!我会尝试使用 FreeTDS 驱动程序 【参考方案1】:

通过 Linux 生成 Windows 身份验证很复杂。 EasySoftDB(商业)曾经能够处理这个问题,而 FreeTDS 有一些复杂的支持。

https://docs.microsoft.com/en-us/sql/connect/odbc/linux-mac/using-integrated-authentication

我的建议是放弃 Windows 身份验证并使用 SQL 身份验证。确实没有安全差异,只是您在连接字符串中提供了用户名和密码。但这会让你的生活更轻松。

【讨论】:

感谢您的建议(我肯定更喜欢使用 SQL 身份验证,但涉及公司政治:P) 那么不要在linux中运行你的服务器,而是使用一个microsoft box,确保你向他们解释许可成本和管理成本。有时,当您开始根据政策提高成本时,他们很快就会改变态度。【参考方案2】:

我最终使用了 pymssql 库,它基本上是 FreeTDS 驱动程序之上的 pyodbc。它开箱即用。

奇怪的是我怎么这么难发现这个库..

【讨论】:

不幸的是pymssql项目已经停止,你应该考虑使用pyodbc 如项目页面所述:“Recent Changes Version 2.1.5 - 2020-09-17 - Mikhail Terekhov General Revert deprecation” 来源:pypi.org/project/pymssql 确实是这个问题的最佳答案。 【参考方案3】:

我试图做同样的事情,在阅读了 OPs 的答案后,我测试了 pymssql 并注意到它只适用于以下内容:

pymssql.connect(server='myserver', user='domain\username', password='password', database='mydb')

在意识到这就是 pymssql 所需要的全部之后,我回到了 pyodbc 并能够使用它:

pyodbc.connect("DRIVER=FreeTDS;SERVER=myserver;PORT=1433;DATABASE=mydb;UID=domain\username;PWD=password;TDS_Version=8.0")

我只是想感谢您发布此内容,因为它对我帮助很大!!!! :)

【讨论】:

【参考方案4】:

您必须获得 Kerberos 票证才能使用。您的示例未指定您的 Linux 系统是否设置为通过 Kerberos 进行身份验证,或者您之前是否在代码命中连接字符串之前获得了 Kerberos 票证。

如果您的 Linux 系统设置为通过 Kerberos 进行身份验证,那么作为概念证明,您可以使用 kinit 从命令行获取 Kerberos 票证。以下是通过 WSL 在 Windows 上的 Ubuntu 中运行的 python3 对我有用的方法。 python代码:

#!/usr/bin/env python

# minimal example using Kerberos auth
import sys
import re
import pyodbc

driver='ODBC Driver 17 for SQL Server'
server = sys.argv[1]
database = sys.argv[2]

# trusted_connection uses kerberos ticket and ignores UID and PASSWORD in connection string
# https://docs.microsoft.com/en-us/sql/connect/odbc/linux-mac/using-integrated-authentication?view=sql-server-ver15

try:
    cnxn = pyodbc.connect(driver=driver, server=server, database=database, trusted_connection='yes')
    cursor = cnxn.cursor()
except pyodbc.Error as ex:
    msg = ex.args[1]
    if re.search('No Kerberos', msg):
        print('You must login using kinit before using this script.')
        exit(1)
    else:
        raise

# Sample select query
cursor.execute("SELECT @@version;")
row = cursor.fetchone()
while row:
    print(row[0])
    row = cursor.fetchone()
print('success')

这会告诉您是否没有票。由于它使用票证,因此您不必在脚本中指定用户或密码。它会忽略两者。

现在我们运行它:

user@localhost:~# kdestroy # make sure there are no active tickets
kdestroy: No credentials cache found while destroying cache

user@localhost:~# python pyodbc_sql_server_test.py tcp:dbserver.example.com mydatabase
You must login using kinit before using this script.

user@localhost:~# kinit
Password for user@DOMAIN.LOCAL:

user@localhost:~# python pyodbc_sql_server_test.py tcp:dbserver.example.com mydatabase
Microsoft SQL Server 2016 (SP2-GDR) (KB4505220) - 13.0.5101.9 (X64)
        Jun 15 2019 23:15:58
        Copyright (c) Microsoft Corporation
        Enterprise Edition (64-bit) on Windows Server 2016 Datacenter 10.0 <X64> (Build 14393: )

success

user@localhost:~#

您也可能成功地从建立此连接之前运行的 python 代码获得了 Kerberos 票证,但这超出了此答案的范围。搜索 python Kerberos 模块可能会为您指明解决方案。

似乎还可以设置 Linux 系统,以便用户登录后立即自动获得可以传递给其他进程的 Kerberos 票证。这也超出了此答案的范围,但在 Linux 登录时搜索自动 Kerberos 票证可能会产生一些线索。

【讨论】:

谢谢。您是否知道如果我使用 kinit 为另一个用户(不同于运行进程的用户)获取票证,ODBC 驱动程序将在连接时使用该票证?或者有没有办法指定自定义用户?由于 UID 和 PWD 选项将被忽略 @LuisLezcanoAiraldi 好问题。我想 pyodbc 会尝试它找到的任何票,无论票中的用户是否与登录用户匹配,但这纯粹是猜测。不过还有更多的谜团:显然,不同的域/用户可以有多个活动票证。我不知道在这种情况下 pyodbc 会做什么。【参考方案5】:

我为同一任务找到了两种方法。我有带有 AD auth 的 MSSQL 服务器。

您可以使用 JVM。 加载并安装 JAVA https://www.oracle.com/technetwork/java/javase/downloads/jre8-downloads-2133155.html。同时安装 JPype1 版本 0.6.3 pip install JPype==0.6.3。高于 0.6.3 的版本将无法正常工作

import jaydebeapi
import pandas as pd
driver_name = "net.sourceforge.jtds.jdbc.Driver"
connection_url="jdbc:jtds:sqlserver://<server>:<port>/<database name>"
connection_properties = 
"domain": "<domain name>",
"user": "<username>",
"password": "<pwd>"
jar_path =  <path to jsds>"/jtds-1.3.1.jar"
CONN = jaydebeapi.connect(driver_name, connection_url, connection_properties, jar_path)
sql = "SELECT * FROM INFORMATION_SCHEMA.COLUMNS"
df = pd.read_sql(sql, CONN)

这个版本对我来说太慢了。

您还可以通过 FreeTDS 使用 pyodbc。创建 FreeTDS 连接 在您的 Linux apt-get install tdsodbc freetds-bin 上安装 FreeTDS,像这样配置 FreeTDS /etc/odbcinst.ini

[FreeTDS]
Description=FreeTDS
Driver=/usr/lib/x86_64-linux-gnu/odbc/libtdsodbc.so
Setup=/usr/lib/x86_64-linux-gnu/odbc/libtdsS.so

然后开启odbcinst -i -d -f /etc/odbcinst.ini

之后就可以使用pyodbc了

import pandas as pd
import pyodbc    
CONN =pyodbc.connect('DRIVER=FreeTDS;'
                                  'Server=<server>;'
                                  'Database=<database>;'
                                  'UID=<domain name>\\<username>;'
                                  'PWD=<password>;'
                                  'TDS_Version=8.0;'
                                  'Port=1433;')
sql = "SELECT * FROM INFORMATION_SCHEMA.COLUMNS"
df = pd.read_sql(sql, CONN)

它的工作速度更快

【讨论】:

Centos 7: yum install freetds freetds-devel;驱动程序=/usr/lib64/libtdsodbc.so 安装程序=/usr/lib64/libtdsS.so

以上是关于使用 pyodbc 从 Linux 向 Windows SQL Server 进行身份验证的主要内容,如果未能解决你的问题,请参考以下文章

linux使用pyodbc和freetds连接sqlserver

如何在 Linux 上使用 pyodbc 对 Active Directory 帐户使用用户/密码身份验证

linux上的Django-pyodbc SQL Server/freetds服务器连接问题

pyodbc - 使用默认值将列添加到 MS Access

使用 pyodbc 从 SQL 中检索数据

Linux上的pyodbc fast_executemany在插入时出现乱码