鏈接SQL Server數據庫時發生報錯「The target principal name is incorrect. Cannot generate SSPI context」,沒法鏈接,多是因爲AD域中記錄了錯誤的SPN,致使沒法進行身份驗證而鏈接失敗。下文經過簡述Kerberos認證過程、SPN的組成,引出由SPN錯誤引起報錯的解決方法。html
Kerberos認證須要包含KDC(Key Distribution Center)、客戶端用戶、提供服務的服務器三個組件。其中KDC是域控的一部分,執行兩個任務:認證服務(AS)、票據許可服務(TGS)ios
當客戶端用戶登陸到網絡時,會向用戶所在域的AS申請一個「票據請求票據」(TGT);數據庫
當客戶端要訪問網絡上某個資源時,須要出示TGT、認證碼、SPN(Server Principal Name),藉此從用戶所在域的TGS獲取session票據;編程
客戶端使用這個session票據和認證碼向網絡上的服務獲取訪問令牌,接下來就能夠登陸上該服務了。windows
客戶端和服務器須要加域,當客戶端和服務器加入不一樣域時,兩個域須要有相互信任關係;服務器
提供服務的服務器須要註冊正確的SPN。網絡
注:從Windows Server 2003開始默認使用Kerberos認證方式,當網絡上沒有註冊SPN時,就會使用NTLM認證方式,這個步驟叫作NTLM Fallback;若是網絡上有註冊SPN,但這個SPN註冊在了錯誤的帳戶下(例如不是SQL Server服務啓動帳號),則認證失敗,且不會再次嘗試NTLM認證。session
SPN是服務器上所運行服務的惟一標示,每一個使用Kerberos的服務都須要一個SPN,這樣客戶端才能夠辨認這個服務。SPN須要註冊在AD域的計算機帳戶或者域用戶帳戶下。app
一個SQL Server的SPN由如下元素組成:dom
服務類型:標示了服務的泛用類。對於SQL Server而言,是MSSQLSvc。
主機:有兩種形式。一個是運行SQL Server的計算機的FQDN。還有一種就是SQL Server的計算機的netbios名字,俗稱短名。
端口號/實例名:服務所監聽的計算機端口號。對於SQL Server而言,若是SQL運行在默認端口(1433)上,則端口號能夠省略。
從SQL Server 2008開始,Kerberos能夠支持TCP, Named Pipes和Shared Memory三種協議。所以對於SQL Server 2008咱們也可使用SQL Server的實例名來替代端口號(僅就命名實例而言)。
例如:
MSSQLSvc/myserver.corp.mycomany.com:1433
MSSQLSvc/myserver:1433
MSSQLSvc/myserver.corp.mycomany.com
MSSQLSvc/myserver:
MSSQLSvc/myserver.corp.mycomany.com:instancename
MSSQLSvc/myserver:instancename
注:推薦爲FQDN和netbios都註冊SPN。
詳細的使用方法參考微軟官方文檔:
https://docs.microsoft.com/zh-cn/previous-versions/windows/it-pro/windows-server-2012-r2-and-2012/cc731241(v=ws.11)
查詢SPN:
在命令行輸入:
Setspn -L <Account>
其中<Account>能夠是計算機帳戶或者域用戶帳戶。
添加SPN:
在命令行輸入:
Setspn -S MSSQLSvc/server4.main.local:1433 <Account>
注:使用「Setspn -A」也能夠添加SPN,但推薦使用「Setspn -S」,由於「Setspn -S」在添加前會檢查域內是否存在相同的SPN,防止重複的SPN註冊在不一樣的帳戶下。
命令行輸入:
Setspn -X
也能夠檢查域內是否存在重複的SPN。
刪除SPN:
在命令行輸入:
Setspn -D MSSQLSvc/server4.main.local:1433 <Account>
使用Network Service或Local System
內置帳戶Network Service和Local System表明計算機自己,SPN須要註冊在運行SQL Server的計算機帳戶下。但Network Service和Local System自己有權限爲本機註冊和刪除SPN,通常狀況不須要手動修改。(Local System權限過大,不推薦使用作服務啓動帳戶)
使用域用戶帳戶
通常域用戶沒有爲自身註冊SPN的權限,須要手動在該域用戶帳戶下注冊SPN;若是該域用戶具備本地管理員或域管理員權限,則有權限爲自身註冊或刪除SPN。
注:能夠在域控中爲特定帳戶添加註冊SPN的權限,但官方不推薦這種作法。
文字開頭提到的報錯:「Cannot generate SSPI context」
本次處理的故障是因爲更換了服務啓動帳戶,舊的SPN註冊在本地計算機帳戶下,更換後沒有自動刪除,致使域內存在不正確的SPN,沒法完成Kerberos認證。
解決方法:
刪除計算機帳戶下的SPN後,添加域用戶帳戶下的SPN。操做步驟以下:
先查詢SPN,命令行運行
Setspn -L server4
確認存在錯誤的SPN,下一步刪除,命令行執行
Setspn -D MSSQLSvc/server4.main.local:1433 server4
Setspn -D MSSQLSvc/server4.main.local server4
刪除後再爲域用戶帳戶添加SPN,命令行執行
Setspn -S MSSQLSvc/server4.main.local user-c
Setspn -S MSSQLSvc/server4.main.local:1433 user-c
添加成功後,再次查詢SPN確認,命令行執行
Setspn -L server4
Setspn -L user-c
添加成功,檢查報錯是否還存在,在SSMS執行查詢
select auth_scheme,* from sys.dm_exec_connections
鏈接成功,並且使用的是Kerberos認證。
"Login Failed for user 'NT Authority\ANONYMOUS' LOGON"
客戶端可能正在使用Local System進行鏈接,並且SQL Server沒有註冊SPN,因爲Local System帳號繼承自System Context而不是一個真實的user context,因而就被當成ANONYMOUS LOGON。
解決方法:在SQL Server服務啓動帳戶下手動註冊SPN。
"Login Failed for user ' ', the user is not associated with a trusted SQL Server connection"
這種狀況是客戶端用戶沒能被SQL Server識別出:
若是客戶端程序是運行在一個本機用戶(非域用戶)或者是一個非本機管理員權限的機器賬戶(非local system)下,那麼不管SQL Server是否有註冊SPN,都會獲得這個錯誤。
解決方法:
在服務器端建立一個和客戶端用戶「同用戶名用密碼」的本機帳號,而後在SQL Server中賦予相應的登陸權限。這就是所謂pass through的方式。此時你其實是在使用SQL Server那臺計算機的同名賬戶來訪問SQL Server和相關的其餘資源。所以SQL Server機器上該賬戶的權限設置決定了客戶端的操做權限。
若是客戶端應用程序是運行在一個域用戶下的話,那麼該錯誤就說明Kerberos的驗證失敗了,這每每是因爲沒有SPN或者SPN不正確形成的。
解決方法:
註冊正確的SPN,或者刪除相應SPN放棄使用Kerberos認證。
"Could not open a connection to SQL Server[1326]"
和上面提到的故障狀況相似,但上面使用TCP鏈接,這裏咱們使用Named Pipe鏈接,解決方法同樣。
"Login failed for user '<domain>\<machinename>$' "
客戶端可能在使用Local system或者Network service運行。
解決方法:
在SQL Server的login中添加一個"domain\machinename$"帳號。其中Machinename是客戶端的計算機名。