sql >> Databasteknik >  >> RDS >> Sqlserver

Gå med SQL Server-drivrutinen kan inte ansluta, inloggningen misslyckades

Jag vill dela med mig av min erfarenhet av att arbeta fram ett enkelt demoprogram för Go-språkdatabas med SQL Server Express 2008. Jag tror att följande lärdomar kommer att gälla för alla SQL Server-versioner från 2008 och senare.

My SQL Server Express har tidigare installerats med default instans snarare än en named exempel. Den installerades också för att använda Windows-autentisering. Båda dessa inställningar krävdes av annat utvecklingsarbete som jag gör. Det andra arbetet som jag gör använder SQL Server Express på samma PC som applikationen som en lokal databasmotor. Jag förväntade mig att kunna använda Windows-autentisering med SQL Server i min Go-applikation.

Jag letade efter en drivrutin och ett litet exempelprogram att använda med en lokal SQL Server och Go, den här frågan kom upp i min sökning. Jag tänkte lägga till lite ytterligare information och ett exempelprogram för att hjälpa andra att komma igång och lära av mina misstag. Jag tyckte också att den här artikeln GoLang och MSSQL-databaser:Ett exempel var till hjälp, särskilt efter att jag gjorde tillräckligt många misstag för att jag förstod det bättre.

Den slutliga versionen av mitt testprogram är som följer:

package main

import (
    "fmt"
    "log"
    "database/sql"
     _ "github.com/denisenkom/go-mssqldb"     // the underscore indicates the package is used
)    

func main() {
    fmt.Println("starting app")

    // the user needs to be setup in SQL Server as an SQL Server user.
    // see create login and the create user SQL commands as well as the
    // SQL Server Management Studio documentation to turn on Hybrid Authentication
    // which allows both Windows Authentication and SQL Server Authentication.
    // also need to grant to the user the proper access permissions.
    // also need to enable TCP protocol in SQL Server Configuration Manager.
    //
    // you could also use Windows Authentication if you specify the fully qualified
    // user id which would specify the domain as well as the user id.
    // for instance you could specify "user id=domain\\user;password=userpw;".

    condb, errdb := sql.Open("mssql", "server=localhost;user id=gouser;password=g0us3r;")
    if errdb  != nil {
        fmt.Println("  Error open db:", errdb.Error())
    }

    defer condb.Close()

    errdb = condb.Ping()
    if errdb != nil {
        log.Fatal(errdb)
    }

    // drop the database if it is there so we can recreate it
    // next we will recreate the database, put a table into it,
    // and add a few rows.
    _, errdb = condb.Exec("drop database mydbthing")
    if errdb != nil {
        fmt.Println("  Error Exec db: drop db - ", errdb.Error())
    }

    _, errdb = condb.Exec("create database mydbthing")
    if errdb  != nil {
        fmt.Println("  Error Exec db: create db - ", errdb.Error())
    }

    _, errdb = condb.Exec("use  mydbthing")
    if errdb  != nil {
        fmt.Println("  Error Exec db: using db - ", errdb.Error())
    }

    _, errdb = condb.Exec("create table junky (one int, two int)")
    if errdb  != nil {
        fmt.Println("  Error Exec db: create table - ", errdb.Error())
    }

    _, errdb = condb.Exec("insert into junky (one, two) values (101, 201)")
    if errdb  != nil {
        fmt.Println("  Error Exec db: insert table 1 - ", errdb.Error())
    }
    _, errdb = condb.Exec("insert into junky (one, two) values (102, 202)")
    if errdb  != nil {
        fmt.Println("  Error Exec db: insert table 2 - ", errdb.Error())
    }
    _, errdb = condb.Exec("insert into junky (one, two) values (103, 203)")
    if errdb  != nil {
        fmt.Println("  Error Exec db: insert table 3 - ", errdb.Error())
    }

    // Now that we have our database lets read some records and print them.
    var (
        one  int
        two  int
    )

    // documentation about a simple query and results loop is at URL
    // http://go-database-sql.org/retrieving.html
    // we use Query() and not Exec() as we expect zero or more rows to
    // be returned. only use Query() if rows may be returned.
    fmt.Println ("  Query our table for the three rows we inserted.")
    rows, errdb := condb.Query ("select one, two from junky")
    defer rows.Close()
    for rows.Next() {
        err:= rows.Scan (&one, &two)
        if err != nil {
            fmt.Println("  Error Query db: select - ", err.Error())
        } else {
            fmt.Printf("    - one %d and two %d\n", one, two)
        }
    }
    rows.Close()

    errdb = rows.Err()
    if errdb != nil {
        fmt.Println("  Error Query db: processing rows - ", errdb.Error())
    }

    fmt.Println("ending app")
}

Första gången ovanstående applikation körs när de nödvändiga ändringarna av SQL Server-inställningarna har gjorts, kommer den att generera följande utdata. Eftersom databasen inte finns första gången programmet körs kommer du att se felmeddelandet utskrivet. Men efterföljande gånger den körs kommer databasen att finnas och felmeddelandet när databasen släpps kommer inte att matas ut.

starting app
  Error Exec db: drop db -  mssql: Cannot drop the database 'mydbthing', because it does not exist or you do not have permission.
  Query our table for the three rows we inserted.
    - one 101 and two 201
    - one 102 and two 202
    - one 103 and two 203
ending app

Installera SQL Server Driver-paketet

Det första jag var tvungen att göra var att hitta ett databasdrivrutinpaket som skulle fungera med SQL Server. Flera stackoverflow-inlägg rekommenderas github.com/denisenkom/go-mssqldb så det är vad som används.

För att använda github.com/denisenkom/go-mssqldb Jag var tvungen att först hämta det från github-förvaret med go get github.com/denisenkom/go-mssqldb från kommandoskalsfönstret skapat genom att köra Git Shell .

Git Shell är github-skalet som installeras som en del av installationen av Git. Jag upptäckte att jag var tvungen att köra go get kommandot i Git Shell för att go kommandot för att hitta git applikationen och få tillgång till github-förvaret. När jag försökte köra go get kommando från ett normalt kommandoskal Jag såg ett felmeddelande som indikerar att git kommandot kunde inte hittas.

Efter installation av go-mssqldb paket Jag kunde köra min exempelapplikation och fortsatte att stöta på ett körtidsfel från Open() . Resultatet från min applikation var följande:

starting app

Error Exec db: create db -  Unable to open tcp connection with host 'localhost:1433': dial tcp 127.0.0.1:1433: connectex: No connection could be made because the target machine actively refused it.

ending app

Aktivera TCP-anslutningar för SQL Server

Efter lite sökning hittade jag ett antal olika sajter som alla indikerade att felet innebar att min SQL Server-instans inte var konfigurerad för TCP/IP. De olika inläggen angav att jag behövde använda Sql Server Configuration Manager för att aktivera TCP/IP.

Det jag upptäckte är att det faktiskt finns två ställen där TCP/IP måste aktiveras. Ett var Client Protocols och det var verkligen redan aktiverat. Den andra var dock Protocols for MSSQLSERVER och i den ena var TCP/IP inaktiverad. Så jag aktiverade TCP/IP i Protocols for MSSQLSERVER och startade sedan om SQL Server-tjänsten med hjälp av tjänsteverktyget i administrationsverktygen från kontrollpanelen.

Men jag hade fortfarande problem med någon typ av fråga efter att ha använt sql.Open() . Jag såg applikationsutdata som var en variant av följande. Felmeddelandet var detsamma men när funktionsanrop hade fel kunde ändras från en körning till nästa. Jag försökte ändra anslutningssträngen som anges i sql.Open() utan andra resultat än olika felmeddelanden.

starting app
  Error Exec db: create db -  driver: bad connection
  Error Exec db: create table -  driver: bad connection
ending app

När jag letade vidare hittade jag denna anteckning i github-förvaret:

Kända problem

SQL Server 2008 och 2008 R2-motorer kan inte hantera inloggningsposter när SSL-kryptering inte är inaktiverad. För att fixa SQL Server 2008 R2-problem, installera SQL Server 2008 R2 Service Pack 2. För att fixa SQL Server 2008problem, installera Microsoft SQL Server 2008 Service Pack 3 och Cumulativeupdate-paket 3 för SQL Server 2008 SP3. Mer information:http://support.microsoft.com/kb/2653857

Så jag laddade ner uppdateringarna som jag faktiskt aldrig installerade. Medan jag väntade på nedladdningen, letade jag runt mer och hittade mappen som innehåller den faktiska SQL Server-körbara filen tillsammans med Log mapp som innehåller en serie filer ERRORLOG , ERRORLOG.1 , etc.

SQL Server-loggar indikerar att SQL Server-användare krävs

Tittar i ERRORLOG fil Jag hittade en fellogg för SQL Server med följande loggar som gav nästa pusselbit:

2016-08-15 22:56:22.41 Server      SQL Server is now ready for client connections. This is an informational message; no user action is required.
2016-08-15 23:55:47.51 Logon       Error: 18456, Severity: 14, State: 58.
2016-08-15 23:55:47.51 Logon       Login failed for user 'rchamber'. Reason: An attempt to login using SQL authentication failed. Server is configured for Windows authentication only. [CLIENT: 127.0.0.1]
2016-08-15 23:55:47.61 Logon       Error: 18456, Severity: 14, State: 58.
2016-08-15 23:55:47.61 Logon       Login failed for user 'rchamber'. Reason: An attempt to login using SQL authentication failed. Server is configured for Windows authentication only. [CLIENT: ::1]
2016-08-15 23:55:47.62 Logon       Error: 18456, Severity: 14, State: 58.
2016-08-15 23:55:47.62 Logon       Login failed for user 'rchamber'. Reason: An attempt to login using SQL authentication failed. Server is configured for Windows authentication only. [CLIENT: 127.0.0.1]

Jag insåg då att Go SQL Server-drivrutinen inte använde Windows-autentisering utan istället använde SQL Server-autentisering. Jag hade försökt använda Windows-autentisering genom att ange ett tomt user id= men det verkade inte fungera. Så med hjälp av sqlcmd verktyget skapade jag en SQL Server-användare.

1> create login gouser with password='g0us3r';
2> go
1> create user gouser for login gouser;
2> go

Därefter laddade jag ner och installerade Microsoft SQL Server Management Studio. Detta är ett annat verktyg än SQL Server Configuration Manager. Med detta gjorde jag två saker:(1) aktiverade SQL Server-autentisering samt Windows-autentisering och (2) gav nödvändiga behörigheter för min nya SQL Server-användare gouser . Detta verktyg gav också ett trevligt användargränssnitt för att bläddra i SQL Server och dess olika databaser.

Se till att SQL-användaren du skapar har tillräckliga behörigheter så att den kan användas för att ansluta till SQL Server och skapa en databas.

Några överväganden för att använda Windows-autentisering

Efter ytterligare forskning fann jag att jag faktiskt kunde använda Windows-autentisering, men det fullständigt kvalificerade användar-ID och dess lösenord måste anges. För en miljö som använder Active Directory med domännamnet "AD" skulle det fullt kvalificerade användar-ID:t vara "AD\userid" och för den lokala värden skulle det vara "\userid". Jag forskar fortfarande om att automatiskt kunna använda inloggningsuppgifterna för den för närvarande inloggade användaren.

Efter ytterligare forskning och hitta hjälp från Go-drivrutinutvecklarna, bör Windows-autentisering med den nuvarande vara möjlig om sql.Open() inkluderar inte användarinformationen som betyder "användar-id=;lösenord=;" bör inte anges.

Denna form av automatisk Windows-autentisering mot den aktuella användaren är dock endast tillåten om SQL Server-instansen använder Kerberos med ett giltigt Service Principal Name (SPN). Om du utför en omstart av din instans av SQL Server och du ser följande logg i din ERRORLOG-fil, kunde SQL Server inte initieras med Kerberos.

2016-08-23 18:32:16.77 Server SQL Server Network Interface-biblioteket kunde inte registrera Service Principal Name (SPN) för SQL Server-tjänsten. Fel:0x54b, tillstånd:3. Om en SPN inte registreras kan den integrerade autentiseringen falla tillbaka till NTLM istället för Kerberos. Detta är ett informationsmeddelande. Ytterligare åtgärder krävs bara om Kerberos-autentisering krävs av autentiseringspolicyer.

Se även Hur du säkerställer att du använder Kerberos-autentisering när du skapar en fjärranslutning till en instans av SQL Server 2005 som också tillhandahåller ytterligare information med hjälp av setspn kommando för att åtgärda problemet.

Se även SQL Network Interface-biblioteket kunde inte registrera SPN.

Om betrodd Windows-autentisering (Uppdaterad enligt begäran från @Richard av @xpt)

Windows-autentisering loggar in på SQL Server med Windows-uppgifter utan att ange ett användar-ID och lösenord. Detta kallas betrodd anslutning för sqlcmd eller ODBC; eller kallas Single-Sign-On för go-mssqldb Go drivrutinspaket.

Från go-mssqldb 's readme i github,

"användar-id" - ange SQL Server Authentication-användar-id eller WindowsAuthentication-användar-id i formatet DOMAIN\User. I Windows, om användar-ID är tomt eller saknas används Single-Sign-On.

Så jag försökte följande två sätt med min SQL Server 2008 R2 och båda fungerar bara bra:

condb, errdb := sql.Open("mssql", "server=MyServer;user id=;password=DONTCARE;")
condb, errdb := sql.Open("mssql", "server=MyServer;user id=;password=;")

Observera att användning av server=localhost skulle misslyckas, eftersom det är viktigt att ha rätt värdnamn, från det namnet bygger drivrutinen SQL Server kerberos Service Principal Name (SPN) och det namnet måste matcha SQL Servers. Jag använde ett korrekt Service Principal Name (SPN) med mitt test så det fungerar.




  1. Hur man får alla tabeller som har en primär nyckelbegränsning skapad i SQL Server Database - SQL Server / TSQL Tutorial 57

  2. Det gick inte att skapa den begärda tjänsten [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment]

  3. Lista över lagrade procedurer/funktioner Mysql Command Line

  4. NOT IN i postgresql fungerar inte