[從 .NET Framework 4.5 開始,Windows Identity Foundation (WIF) 已完全整合到 .NET Framework 中。 本文涉及的 WIF 版本,WIF 3.5,已被淘汰,應僅在開發 .NET Framework 3.5 SP1 或 .NET Framework 4 時使用。 如需 .NET Framework 4.5 中 WIF 的詳細資訊,也稱為 WIF 4.5,請參閱 .NET Framework 4.5 開發指南中的 Windows Identity Foundation 檔。
此案例描述需要存取需要身分識別委派鏈結來執行訪問控制檢查的後端資源的應用程式。 簡單的身分識別委派鏈結通常由初始呼叫端和立即呼叫端的身分識別資訊所組成。
使用 Windows 平臺上的 Kerberos 委派模型,後端資源只能存取立即呼叫端的身分識別,而不是存取初始呼叫者的身分識別。 此模型通常稱為受信任的子系統模型。 WIF 使用 Actor 屬性,保持初始呼叫者的身分識別以及委派鏈中的直接呼叫者。
下圖說明一般身分識別委派案例,其中 Fabrikam 員工會存取 Contoso.com 應用程式中公開的資源。
參與此案例的虛構使用者如下:
- Frank:想要存取 Contoso 資源的 Fabrikam 員工。
- Daniel:在應用程式中實作必要變更的 Contoso 應用程式開發人員。
- Adam:Contoso IT 系統管理員。
此案例所涉及的元件如下:
- web1:具有後端資源連結的 Web 應用程式,需要初始呼叫端的委派身分識別。 此應用程式是使用 ASP.NET 所建置。
- 存取 SQL Server 的 Web 服務,其需要初始呼叫端的委派身分識別,以及立即呼叫端的身分識別。 此服務是使用 WCF 所建置。
- sts1:屬於宣告提供者角色的 STS,並傳遞應用程式預期的宣告(web1)。 它已建立與 Fabrikam.com 以及應用程式的信任。
- sts2:作為 Fabrikam.com 的身分識別提供者角色的 STS,並提供 Fabrikam.com 員工用來驗證的端點。 它已與 Contoso.com 建立信任,讓 Fabrikam 員工能夠存取 Contoso.com 上的資源。
備註
通常在此案例中使用的「ActAs 令牌」一詞是指 STS 所發出的令牌,並包含使用者的身分識別。 Actor 屬性包含 STS 的身分識別。
如上圖所示,此案例中的流程為:
- Contoso 應用程式已設定為取得 ActAs 令牌,其中包含 Fabrikam 員工的身分識別,以及 Actor 屬性中的即時呼叫者的身分識別。 Daniel 已對應用程式實作這些變更。
- Contoso 應用程式已設定為將 ActAs 令牌傳遞至後端服務。 Daniel 已對應用程式實作這些變更。
- Contoso Web 服務已設定為呼叫 sts1 來驗證 ActAs 令牌。 Adam 已啟用 sts1 來處理委派要求。
- Fabrikam 使用者 Frank 會存取 Contoso 應用程式,並提供後端資源的存取權。
設定身份提供者 (IP)
Fabrikam.com 系統管理員 Frank 有三個選項可供使用:
- 購買並安裝 STS 產品,例如 Active Directory® 同盟服務(AD FS)。
- 訂閱雲端 STS 產品,例如 LiveID STS。
- 使用 WIF 建置自定義 STS。
在此範例案例中,我們假設 Frank 會選取 option1,並將 AD FS 安裝為 IP-STS。 他也會設定名為 \windowsauth 的端點來驗證使用者。 Frank 參考 AD FS 產品檔,並與 Contoso IT 系統管理員 Adam 交談,與 Contoso.com 網域建立信任。
設定宣告提供者
Contoso.com 系統管理員 Adam 可用的選項,與識別提供者先前所述的選項相同。 在此範例案例中,我們假設Adam會選取選項1,並將AD FS 2.0安裝為 RP-STS。
與IP和應用程式建立信任關係
藉由參考AD FS檔,Adam會在 Fabrikam.com 與應用程式之間建立信任。
設定委派功能
AD FS 提供委派處理。 藉由參考 AD FS 文件,Adam 啟用 ActAs 令牌的處理程序。
應用程式特定變更
必須進行下列變更,才能將身分識別委派的支援新增至現有的應用程式。 Daniel 會使用 WIF 進行這些變更。
- 快取 web1 從 sts1 收到的引導令牌。
- 使用 CreateChannelActingAs 及發行的令牌來建立與後端 Web 服務連接的通道。
- 調用後端服務的方法。
快取啟動程式令牌
引導令牌是 STS 發行的第一個令牌,應用程式會從中提取宣告。 在此範例案例中,sts1 會針對使用者 Frank 發出此令牌,而應用程式會快取它。 下列程式代碼範例示範如何在 ASP.NET 應用程式中擷取啟動程式令牌:
// Get the Bootstrap Token
SecurityToken bootstrapToken = null;
IClaimsPrincipal claimsPrincipal = Thread.CurrentPrincipal as IClaimsPrincipal;
if ( claimsPrincipal != null )
{
IClaimsIdentity claimsIdentity = (IClaimsIdentity)claimsPrincipal.Identity;
bootstrapToken = claimsIdentity.BootstrapToken;
}
WIF 提供 CreateChannelActingAs 方法,這個方法會建立指定類型的通道,以指定的安全性令牌做為 ActAs 元素來增強令牌發行要求。 您可以將啟動程式令牌傳遞至此方法,然後在傳回的通道上呼叫必要的服務方法。 在此範例案例中,Frank 的身分識別將 Actor 屬性設定為 web1 的身分識別。
下列代碼段示範如何使用 CreateChannelActingAs 呼叫 Web 服務,然後在傳回的通道上呼叫其中一個服務的方法 ComputeResponse:
// Get the channel factory to the backend service from the application state
ChannelFactory<IService2Channel> factory = (ChannelFactory<IService2Channel>)Application[Global.CachedChannelFactory];
// Create and setup channel to talk to the backend service
IService2Channel channel;
lock (factory)
{
// Setup the ActAs to point to the caller's token so that we perform a
// delegated call to the backend service
// on behalf of the original caller.
channel = factory.CreateChannelActingAs<IService2Channel>(callerToken);
}
string retval = null;
// Call the backend service and handle the possible exceptions
try
{
retval = channel.ComputeResponse(value);
channel.Close();
} catch (Exception exception)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("An unexpected exception occurred.");
sb.AppendLine(exception.StackTrace);
channel.Abort();
retval = sb.ToString();
}
網頁服務特定變更
由於 Web 服務是以 WCF 建置並針對 WIF 啟用,因此一旦使用具有適當簽發者位址的 IssuedSecurityTokenParameters 設定系結之後,WIF 會自動處理 ActA 的驗證。
Web 服務會公開應用程式所需的特定方法。 服務上不需要特定的程式代碼變更。 下列程式代碼範例示範使用 IssuedSecurityTokenParameters 設定 Web 服務:
// Configure the issued token parameters with the correct settings
IssuedSecurityTokenParameters itp = new IssuedSecurityTokenParameters( "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1" );
itp.IssuerMetadataAddress = new EndpointAddress( "http://localhost:6000/STS/mex" );
itp.IssuerAddress = new EndpointAddress( "http://localhost:6000/STS" );
// Create the security binding element
SecurityBindingElement sbe = SecurityBindingElement.CreateIssuedTokenForCertificateBindingElement( itp );
sbe.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10;
// Create the HTTP transport binding element
HttpTransportBindingElement httpBE = new HttpTransportBindingElement();
// Create the custom binding using the prepared binding elements
CustomBinding binding = new CustomBinding( sbe, httpBE );
using ( ServiceHost host = new ServiceHost( typeof( Service2 ), new Uri( "http://localhost:6002/Service2" ) ) )
{
host.AddServiceEndpoint( typeof( IService2 ), binding, "" );
host.Credentials.ServiceCertificate.SetCertificate( "CN=localhost", StoreLocation.LocalMachine, StoreName.My );
// Enable metadata generation via HTTP GET
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
host.Description.Behaviors.Add( smb );
host.AddServiceEndpoint( typeof( IMetadataExchange ), MetadataExchangeBindings.CreateMexHttpBinding(), "mex" );
// Configure the service host to use WIF
ServiceConfiguration configuration = new ServiceConfiguration();
configuration.IssuerNameRegistry = new TrustedIssuerNameRegistry();
FederatedServiceCredentials.ConfigureServiceHost( host, configuration );
host.Open();
Console.WriteLine( "Service2 started, press ENTER to stop ..." );
Console.ReadLine();
host.Close();
}