逐步解說:建立自訂用戶端與服務認證
此主題顯示如何實作自訂用戶端和服務認證,以及如何使用來自應用程式碼的自訂認證。
認證擴充性類別
ClientCredentials 和 ServiceCredentials 類別是 Windows Communication Foundation (WCF) 安全性擴充性的主要進入點。 這些認證類別提供能夠讓應用程式碼設定認證資訊,以及將認證類型轉換為安全性權杖的 API (「安全性權杖」(Security Token) 是用來在 SOAP 訊息內部傳輸認證資訊的型式)。 這些認證類別的責任可以分為兩部分:
提供 API 讓應用程式設定認證資訊。
執行當做 SecurityTokenManager 實作的處理站。
e ClientCredentials 和 ServiceCredentials 類別都繼承自定義傳回 SecurityTokenManager 之合約的抽象 SecurityCredentialsManager 類別。
如需詳細資訊認證類別以及其在 WCF 安全性架構中所扮演角色的詳細資訊,請參閱安全性架構。
WCF 中提供的預設實作會支援系統提供的認證類型,並且建立能夠處理那些認證類型的安全性權杖管理員。
自訂原因
有幾項自訂用戶端或服務認證類別的原因。 首要需求莫過於變更 WCF 涉及處理系統提供之認證類型的預設安全性行為,特別是基於下列原因:
使用其他擴充點無法進行若干變更。
為了加入新的認證類型。
為了加入新的自訂安全性權杖類型。
此主題描述如何實作自訂用戶端和服務認證,以及如何在應用程式碼使用它們。
第一步
建立自訂認證類別只是第一步,因為自訂認證的原因是要變更關於認證佈建、安全性權杖序列化或驗證的 WCF 行為。 本章節中的其他主題描述如何建立自訂序列化程式和驗證器。 就這一點而言,建立自訂認證類別是所有步驟的第一個主題。 只有在建立自訂認證後才能完成後續動作 (建立自訂序列化程式和驗證器)。 建構在此主題上的其他主題包含:
程序
實作自訂用戶端認證
定義衍生自 ClientCredentials 類別的新類別。
選擇性。 為新的認證類型加入新方法或屬性。 如果您不需要加入新的認證類型,請略過這個步驟。 下列範例即是加入
CreditCardNumber
屬性。覆寫 CreateSecurityTokenManager 方法。 當使用自訂用戶端認證時,WCF 安全性基礎結構會自動呼叫此方法。 這個方法是負責建立和傳回 SecurityTokenManager 類別實作的執行個體。
注意: 請注意,覆寫 CreateSecurityTokenManager 方法以建立自訂安全性權杖管理員是很重要的。 衍生自 ClientCredentialsSecurityTokenManager 的安全性權杖管理員,必須傳回衍生自 SecurityTokenProvider 的自訂安全性權杖提供者,以建立實際的安全性權杖。 若未依照這個模式建立安全性權杖,應用程式在快取 ChannelFactory 物件時 (此乃 WCF 用戶端 Proxy 的預設行為) 可能會運作不正常,以致難免遭受提高權限攻擊。 自訂認證物件是快取為 ChannelFactory 的一部分。 不過,自訂 SecurityTokenManager 則為每次叫用時所建立,因而只要將權仗建立邏輯置於 SecurityTokenManager 中,便能減緩安全性威脅。 覆寫 CloneCore 方法。
public class MyClientCredentials : ClientCredentials { string creditCardNumber; public MyClientCredentials() { // Perform client credentials initialization. } protected MyClientCredentials(MyClientCredentials other) : base(other) { // Clone fields defined in this class. this.creditCardNumber = other.creditCardNumber; } public string CreditCardNumber { get { return this.creditCardNumber; } set { if (value == null) { throw new ArgumentNullException("value"); } this.creditCardNumber = value; } } public override SecurityTokenManager CreateSecurityTokenManager() { // Return your implementation of the SecurityTokenManager. return new MyClientCredentialsSecurityTokenManager(this); } protected override ClientCredentials CloneCore() { // Implement the cloning functionality. return new MyClientCredentials(this); } }
實作自訂用戶端安全性權杖管理員
定義衍生自 ClientCredentialsSecurityTokenManager 的新類別。
選擇性。 若您必須建立自訂 SecurityTokenProvider 實作,即應覆寫 CreateSecurityTokenProvider 方法。如需詳細資訊自訂安全性權仗提供者的詳細資訊,請參閱 HOW TO:建立自訂安全性權杖提供者。
選擇性。 若您必須建立自訂 SecurityTokenAuthenticator 實作,即應覆寫 CreateSecurityTokenAuthenticator 方法。如需詳細資訊自訂安全性權仗驗證器的詳細資訊,請參閱 HOW TO:建立自訂安全性權杖驗證器。
選擇性。 若您必須建立自訂 SecurityTokenSerializer,即應覆寫 CreateSecurityTokenSerializer 方法。如需詳細資訊自訂安全性權杖與自訂安全性權杖序列化程式的詳細資訊,請參閱 HOW TO:建立自訂權杖。
internal class MyClientCredentialsSecurityTokenManager : ClientCredentialsSecurityTokenManager { MyClientCredentials credentials; public MyClientCredentialsSecurityTokenManager(MyClientCredentials credentials) : base(credentials) { this.credentials = credentials; } public override SecurityTokenProvider CreateSecurityTokenProvider( SecurityTokenRequirement tokenRequirement) { // Return your implementation of the SecurityTokenProvider, if required. // This implementation delegates to the base class. return base.CreateSecurityTokenProvider(tokenRequirement); } public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator( SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver) { // Return your implementation of the SecurityTokenAuthenticator, if required. // This implementation delegates to the base class. return base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver); } public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version) { // Return your implementation of the SecurityTokenSerializer, if required. // This implementation delegates to the base class. return base.CreateSecurityTokenSerializer(version); } }
使用來自應用程式碼的自訂用戶端認證
建立所產生之用戶端的執行個體以代表服務介面,或建立 ChannelFactory 的執行個體指向想要通訊的服務。
建立自訂用戶端認證類別的新執行個體,並將其新增至 Behaviors 集合中,您可以透過 Endpoint 屬性存取這個集合。
// Create a client with the client endpoint configuration. CalculatorClient client = new CalculatorClient(); // Remove the ClientCredentials behavior. client.ChannelFactory.Endpoint.Behaviors.Remove<ClientCredentials>(); // Add a custom client credentials instance to the behaviors collection. client.ChannelFactory.Endpoint.Behaviors.Add(new MyClientCredentials());
前面的程序顯示如何使用來自應用程式碼的用戶端認證。您也可以使用應用程式組態檔設定 WCF 認證。 在硬式編碼方面通常偏好使用應用程式組態,因為能夠在不修改原始程式碼、重新編譯和重新部署的情況下修改應用程式參數。
下一個程序描述如何提供自訂認證組態的支援。
建立自訂用戶端認證的組態處理常式
定義衍生自 ClientCredentialsElement 的新類別。
選擇性。 針對想要透過應用程式組態公開的所有其他組態參數新增屬性。 下列範例會新增一個名為
CreditCardNumber
的屬性。覆寫 BehaviorType 屬性以傳回使用組態項目建立之自訂用戶端認證類別的型別。
覆寫 CreateBehavior 方法。 這個方法會根據從組態檔載入的設定,負責建立和傳回自訂認證類別的執行個體。 請呼叫這個方法的基底 ApplyConfiguration 方法,擷取已載入自訂用戶端認證執行個體之系統提供的認證設定。
選擇性。 如果您在步驟 2 新增其他屬性,就需要覆寫 Properties 屬性以登錄組態架構的其他組態設定,才能加以辨認。 結合屬性與基底類別屬性,以便透過這個自訂用戶端認證組態項目設定系統提供的設定。
public class MyClientCredentialsConfigHandler : ClientCredentialsElement { ConfigurationPropertyCollection properties; public override Type BehaviorType { get { return typeof(MyClientCredentials); } } public string CreditCardNumber { get { return (string)base["creditCardNumber"]; } set { if (String.IsNullOrEmpty(value)) { value = String.Empty; } base["creditCardNumber"] = value; } } protected override ConfigurationPropertyCollection Properties { get { if (this.properties == null) { ConfigurationPropertyCollection properties = base.Properties; properties.Add(new ConfigurationProperty( "creditCardNumber", typeof(System.String), string.Empty, null, new StringValidator(0, 32, null), ConfigurationPropertyOptions.None)); this.properties = properties; } return this.properties; } } protected override object CreateBehavior() { MyClientCredentials creds = new MyClientCredentials(); creds.CreditCardNumber = CreditCardNumber; base.ApplyConfiguration(creds); return creds; } }
在擁有組態處理常式類別後,就能夠整合至 WCF 組態架構。 這樣即可在用戶端端點行為項目中使用自訂用戶端認證,如同下一個程序所示。
在應用程式組態中登錄和使用自訂用戶端認證組態處理常式
將 <extensions> 項目和 <behaviorExtensions> 項目新增至組態檔。
將 <add> 項目新增至 <behaviorExtensions> 項目,然後將 name 屬性設定為適當的值。
將 type 屬性設定為完整型別名稱。 同時包含組件名稱和其他組件屬性。
<system.serviceModel> <extensions> <behaviorExtensions> <add name="myClientCredentials" type="Microsoft.ServiceModel.Samples.MyClientCredentialsConfigHandler, CustomCredentials, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> </behaviorExtensions> </extensions> <system.serviceModel>
登錄組態處理常式後,在相同的組態檔中就能夠使用自訂認證項目,而不是系統提供的 <clientCredentials> 項目。 您可以同時使用系統提供的屬性,以及新增至組態處理常式實作的任何新屬性。 下列程式碼範例會使用 creditCardNumber 屬性 (Attribute) 設定自訂屬性 (Property) 的值。
<behaviors> <endpointBehaviors> <behavior name="myClientCredentialsBehavior"> <myClientCredentials creditCardNumber="123-123-123"/> </behavior> </endpointBehaviors> </behaviors>
實作自訂服務認證
定義衍生自 ServiceCredentials 的新類別。
選擇性。 新增新的屬性以提供已新增之新認證值的 API。 如果您不需要新增新的認證值,請略過這個步驟。 下列程式碼範例會新增
AdditionalCertificate
屬性。覆寫 CreateSecurityTokenManager 方法。 當使用自訂用戶端認證時,WCF 基礎結構會自動呼叫這個方法。 這個方法是負責建立和傳回 SecurityTokenManager 類別實作的執行個體 (在下一個程序中會描述)。
選擇性。 覆寫 CloneCore 方法。 只有在將新屬性或內部欄位新增至自訂用戶端認證實作時才會需要這麼做。
public class MyServiceCredentials : ServiceCredentials { X509Certificate2 additionalCertificate; public MyServiceCredentials() { } protected MyServiceCredentials(MyServiceCredentials other) : base(other) { this.additionalCertificate = other.additionalCertificate; } public X509Certificate2 AdditionalCertificate { get { return this.additionalCertificate; } set { if (value == null) { throw new ArgumentNullException("value"); } this.additionalCertificate = value; } } public override SecurityTokenManager CreateSecurityTokenManager() { return base.CreateSecurityTokenManager(); } protected override ServiceCredentials CloneCore() { return new MyServiceCredentials(this); } }
實作自訂服務安全性權杖管理員
定義衍生自 ServiceCredentialsSecurityTokenManager 類別的新類別。
選擇性。 若您必須建立自訂 SecurityTokenProvider 實作,即應覆寫 CreateSecurityTokenProvider 方法。如需詳細資訊自訂安全性權仗提供者的詳細資訊,請參閱 HOW TO:建立自訂安全性權杖提供者。
選擇性。 若您必須建立自訂 SecurityTokenAuthenticator 實作,即應覆寫 CreateSecurityTokenAuthenticator 方法。如需詳細資訊自訂安全性權仗驗證器的詳細資訊,請參閱 HOW TO:建立自訂安全性權杖驗證器主題。
選擇性。 若您必須建立自訂 SecurityTokenSerializer,即應覆寫 CreateSecurityTokenSerializer 方法。如需詳細資訊自訂安全性權杖與自訂安全性權杖序列化程式的詳細資訊,請參閱 HOW TO:建立自訂權杖。
internal class MyServiceCredentialsSecurityTokenManager : ServiceCredentialsSecurityTokenManager { MyServiceCredentials credentials; public MyServiceCredentialsSecurityTokenManager(MyServiceCredentials credentials) : base(credentials) { this.credentials = credentials; } public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement) { // Return your implementation of SecurityTokenProvider, if required. // This implementation delegates to the base class. return base.CreateSecurityTokenProvider(tokenRequirement); } public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator(SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver) { // Return your implementation of SecurityTokenProvider, if required. // This implementation delegates to the base class. return base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver); } public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version) { // Return your implementation of SecurityTokenProvider, if required. // This implementation delegates to the base class. return base.CreateSecurityTokenSerializer(version); } }
使用來自應用程式碼的自訂服務認證
建立 ServiceHost 的執行個體。
從 Behaviors 集合移除系統提供的服務認證行為。
建立自訂服務認證類別的新執行個體,並將其新增至 Behaviors 集合。
// Create a service host with a service type. ServiceHost serviceHost = new ServiceHost(typeof(Service)); // Remove the default ServiceCredentials behavior. serviceHost.Description.Behaviors.Remove<ServiceCredentials>(); // Add a custom service credentials instance to the collection. serviceHost.Description.Behaviors.Add(new MyServiceCredentials());
使用上列程序「To create a configuration handler for custom client credentials」和「To register and use a custom client credentials configuration handler in the application configuration」中描述的步驟加入對組態的支援。 唯一的差別是使用 ServiceCredentialsElement 類別而不是 ClientCredentialsElement 類別,當做組態處理常式的基底類別。 然後可以在使用系統提供 <serviceCredentials>
項目的地方使用自訂服務認證項目。
另請參閱
工作
參考
ClientCredentials
ServiceCredentials
SecurityCredentialsManager
SecurityTokenManager
ClientCredentialsElement
ServiceCredentialsElement