【问题标题】:Authenticate from Linux to Windows SQL Server with pyodbc使用 pyodbc 从 Linux 向 Windows SQL Server 进行身份验证
【发布时间】: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 驱动程序

标签: python sql linux windows pyodbc


【解决方案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
    猜你喜欢
    • 2019-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-29
    • 1970-01-01
    • 2023-03-05
    • 2023-03-19
    相关资源
    最近更新 更多