使用 pyodbc 从 Linux 到 Windows SQL 服务器进行身份验证

Authenticate from Linux to Windows SQL Server with pyodbc

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

我确实有一些限制:

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

我不熟悉 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 服务器实例。

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

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

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

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

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

我试图做同样的事情,在阅读了 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")

我只是想感谢你发布这篇文章,因为它对我帮助很大!!!! :)

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

如果您的 Linux 系统设置为通过 Kerberos 进行身份验证,那么作为概念证明,您可以从命令行使用 kinit 获取 Kerberos 票证。这是通过 WSL 在 python3 运行ning 在 Ubuntu on Windows 中对我有用的方法。 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 票证可能会提供一些线索。

我为同一任务找到了两种方法。我有带 AD 身份验证的 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)

运行速度更快