共用方式為


偵錯 Windows 驗證錯誤

使用 Windows 驗證作為安全性機制時,安全性支援提供者介面 (SSPI) 會處理安全性程式。 SSPI 層發生安全性錯誤時,會由 Windows Communication Foundation (WCF) 呈現它們。 本主題提供一組架構和問題,以協助診斷錯誤。

如需 Kerberos 通訊協定的概觀,請參閱 Kerberos 說明;如需 SSPI 的概觀,請參閱 SSPI

針對 Windows 驗證,WCF 通常會使用 交涉 安全性支援提供者 (SSP),在客戶端和服務之間執行 Kerberos 相互驗證。 如果 Kerberos 通訊協定無法使用,WCF 預設會回復為 NT LAN Manager (NTLM)。 不過,您可以將 WCF 設定為只使用 Kerberos 通訊協定(並在 Kerberos 無法使用時擲回例外狀況)。 您也可以將 WCF 設定為使用 Kerberos 通訊協定的限制形式。

偵錯方法

基本方法如下所示:

  1. 判斷您是否使用 Windows 驗證。 如果您使用任何其他配置,則不適用本主題。

  2. 如果您確定使用的是 Windows 驗證,請判斷 WCF 組態是否使用 Kerberos 直接或交涉。

  3. 一旦您判斷組態是否使用 Kerberos 通訊協定或 NTLM,您就可以瞭解正確內容中的錯誤訊息。

Kerberos 通訊協定和 NTLM 的可用性

Kerberos SSP 需要域控制器作為 Kerberos 金鑰發佈中心 (KDC)。 只有在用戶端和服務都使用網域身分識別時,才能使用 Kerberos 通訊協定。 在其他帳戶組合中,會使用NTLM,如下表摘要說明。

數據表標頭會顯示伺服器所使用的可能帳戶類型。 左側數據行會顯示用戶端所使用的可能帳戶類型。

本機使用者 本機系統 網域使用者 網域電腦
本機使用者 NTLM NTLM NTLM NTLM
本機系統 匿名 NTLM 匿名 NTLM 匿名 NTLM 匿名 NTLM
網域使用者 NTLM NTLM Kerberos Kerberos
網域電腦 NTLM NTLM Kerberos Kerberos

具體來說,這四種帳戶類型包括:

  • 本機使用者:僅限機器使用者個人資料。 例如:MachineName\AdministratorMachineName\ProfileName

  • 本機系統:未加入網域之計算機上的內建帳戶 SYSTEM。

  • 網域使用者:Windows 網域上的用戶帳戶。 例如: DomainName\ProfileName

  • 網域運算程序:在已加入 Windows 網域的電腦上執行、具電腦身分識別的程序。 例如: MachineName\Network Service

備註

當呼叫Open類別的ServiceHost方法時,會擷取服務認證。 每當用戶端傳送訊息時,就會讀取客戶端認證。

常見的 Windows 驗證問題

本節討論一些常見的 Windows 驗證問題和可能的補救措施。

Kerberos 通訊協定

Kerberos 協議中的 SPN/UPN 問題

使用 Windows 驗證時,若 SSPI 使用或協商 Kerberos 協議,則用戶端端點使用的 URL 必須在服務 URL 中包含服務主機的完全限定域名。 這假設執行服務的帳戶可以存取計算機 (預設) 服務主體名稱 (SPN) 金鑰,該金鑰是在電腦新增至 Active Directory 網域時建立的,這是執行網路服務帳戶下服務最常完成的。 如果服務無法存取電腦 SPN 金鑰,您必須提供用戶端端點身分識別中執行服務所在帳戶的正確 SPN 或使用者主體名稱(UPN)。 如需 WCF 如何與 SPN 和 UPN 搭配運作的詳細資訊,請參閱 服務識別和驗證

在負載平衡案例中,例如 Web 伺服器陣列或 Web 花園,常見的做法是為每個應用程式定義唯一帳戶、將 SPN 指派給該帳戶,並確保所有應用程式的服務都會在該帳戶中執行。

若要取得服務的帳戶 SPN,您必須是 Active Directory 網域管理員。 如需詳細資訊,請參閱 適用於 Windows 的 Kerberos 技術補充

Kerberos 通訊協定直接要求服務在網域電腦帳戶下執行

ClientCredentialType 屬性設定為 WindowsNegotiateServiceCredential 屬性設定為 false 時,就會發生這種情況,如下列程式代碼所示。

WSHttpBinding b = new WSHttpBinding();
// By default, the WSHttpBinding uses Windows authentication
// and Message mode.
b.Security.Message.NegotiateServiceCredential = false;
Dim b As New WSHttpBinding()
' By default, the WSHttpBinding uses Windows authentication 
' and Message mode.
b.Security.Message.NegotiateServiceCredential = False

若要補救,請在已加入網域的計算機上,使用網域計算機帳戶,例如網路服務來執行服務。

委派需要憑證協商

若要搭配委派使用 Kerberos 驗證協議,您必須使用憑證協商來實作 Kerberos 協議(有時稱為「多腿」或「多步驟」Kerberos)。 如果您在不使用憑證協商的情況下實作 Kerberos 驗證(有時稱為「單次」或「單腿」Kerberos),則將會引發例外狀況。

若要透過憑證協商來實現 Kerberos,請執行下列步驟:

  1. AllowedImpersonationLevel設定為Delegation以實作委派。

  2. 需要 SSPI 協商:

    1. 如果您使用標準系結,請將 NegotiateServiceCredential 屬性設定為 true

    2. 如果您使用自訂系結,請將 AuthenticationMode 項目的 屬性 Security 設定為 SspiNegotiated

  3. 要求 SSPI 協定使用 Kerberos 並禁止使用 NTLM。

    1. 使用下列語句在程式代碼中執行此動作: ChannelFactory.Credentials.Windows.AllowNtlm = false

    2. 或者,您可以將 屬性設定 allowNtlmfalse,以在組態檔中執行此動作。 這個屬性包含在 <視窗中>

NTLM 通訊協定

協商 SSP 退回使用 NTLM,但 NTLM 已停用

屬性 AllowNtlm 設定為 false,這會讓 Windows Communication Foundation (WCF) 在使用 NTLM 時,盡最大努力擲回例外狀況。 將此屬性設定為 false ,可能無法防止NTLM認證透過網路傳送。

以下示範如何停用NTLM的備援機制。

CalculatorClient cc = new
    CalculatorClient("WSHttpBinding_ICalculator");
cc.ClientCredentials.Windows.AllowNtlm = false;
Dim cc As New CalculatorClient("WSHttpBinding_ICalculator")
cc.ClientCredentials.Windows.AllowNtlm = False

NTLM 登入失敗

用戶端認證在服務上無效。 檢查使用者名稱和密碼是否已正確設定,並對應至服務執行所在計算機的已知帳戶。 NTLM 會使用指定的認證登入服務的電腦。 雖然認證在用戶端執行所在的計算機上可能有效,但如果服務的計算機上認證無效,此登入將會失敗。

匿名 NTLM 登入發生,但預設會停用匿名登入

建立用戶端時, AllowedImpersonationLevel 屬性會設定為 Anonymous,如下列範例所示,但伺服器預設不允許匿名登入。 這是因為類別之 屬性的AllowAnonymousLogonsWindowsServiceCredential預設值為 false

下列用戶端程式代碼會嘗試啟用匿名登錄(請注意,預設屬性為 Identification)。

CalculatorClient cc =
    new CalculatorClient("WSHttpBinding_ICalculator");
cc.ClientCredentials.Windows.AllowedImpersonationLevel =
System.Security.Principal.TokenImpersonationLevel.Anonymous;
Dim cc As New CalculatorClient("WSHttpBinding_ICalculator")
cc.ClientCredentials.Windows.AllowedImpersonationLevel = _
System.Security.Principal.TokenImpersonationLevel.Anonymous

下列服務程式代碼會變更預設值,以啟用伺服器的匿名登錄。

Uri httpUri = new Uri("http://localhost:8000/");
ServiceHost sh = new ServiceHost(typeof(Calculator), httpUri);
sh.Credentials.WindowsAuthentication.AllowAnonymousLogons = true;
Dim httpUri As New Uri("http://localhost:8000/")
Dim sh As New ServiceHost(GetType(Calculator), httpUri)
sh.Credentials.WindowsAuthentication.AllowAnonymousLogons = True

如需仿真的詳細資訊,請參閱 委派和模擬

或者,用戶端會使用內建帳戶 SYSTEM,以 Windows 服務的形式執行。

其他問題

客戶端認證未正確設定

Windows 驗證使用的是 WindowsClientCredential 類別的 ClientCredentials 屬性所傳回的 ClientBase<TChannel> 實例,而不是 UserNamePasswordClientCredential。 以下顯示不正確的範例。

CalculatorClient cc = new
    CalculatorClient("WSHttpBinding_ICalculator");
cc.ClientCredentials.UserName.UserName = GetUserName(); // wrong!
cc.ClientCredentials.UserName.Password = GetPassword(); // wrong!
Dim cc As New CalculatorClient("WSHttpBinding_ICalculator")
cc.ClientCredentials.UserName.UserName = GetUserName() ' wrong!
cc.ClientCredentials.UserName.Password = GetPassword() ' wrong!

以下顯示正確的範例。

CalculatorClient cc = new
    CalculatorClient("WSHttpBinding_ICalculator");
// This code returns the WindowsClientCredential type.
cc.ClientCredentials.Windows.ClientCredential.UserName = GetUserName();
cc.ClientCredentials.Windows.ClientCredential.Password = GetPassword();
Dim cc As New CalculatorClient("WSHttpBinding_ICalculator")
' This code returns the WindowsClientCredential type.            
cc.ClientCredentials.Windows.ClientCredential.UserName = GetUserName()
cc.ClientCredentials.Windows.ClientCredential.Password = GetPassword()

無法使用 SSPI

當做伺服器使用時,下列作系統不支援 Windows 驗證:Windows XP Home Edition、Windows XP Media Center Edition 和 Windows Vista Home Edition。

使用不同的身分識別開發和部署

如果您在一部計算機上開發應用程式,並在另一部計算機上部署,並使用不同的帳戶類型在每部計算機上進行驗證,您可能會遇到不同的行為。 例如,假設您在 Windows XP Pro 計算機上使用 SSPI Negotiated 驗證模式開發應用程式。 如果您使用本機用戶帳戶進行驗證,則會使用NTLM通訊協定。 開發應用程式之後,您會將服務部署至 Windows Server 2003 計算機,其會在網域帳戶下執行。 此時,客戶端將無法驗證服務,因為它將使用 Kerberos 和域控制器。

另請參閱