在《類比(Impersonation)與委託(Delegation)》一文中,我們對類比和委託這兩個概念以及相關編程實現進行了詳細說明。如果將類比使用在WCF上面,就意味著WCF可以類比用戶端身份(而不是啟動寄宿進程的Windows帳號)執行服務作業。這篇文章主要介紹WCF關於類比的編程。
一、命令式類比編程
如果我們有一個具有類比層級為Impersonation或者Delegation的WindowsIdentity,我們就可以通過調用其Impersonate對其進行身份類比。在採用WCF認證的情況下,我們可以通過當前ServiceSecurityContext的WindowsIdentity或者PrimaryIdentity擷取到代碼認證用戶端的WindowsIdentity對象,那麼在服務作業中類比用戶端身份就和簡單了。這種在服務作業實現中通過編程的方式實現身份模式可以將服務作業的部分邏輯在類比的用戶端身份下執行。
1: using (WindowsImpersonationContext context = ServiceSecurityContext.Current.WindowsIdentity.Impersonate())
2: {
3: //在類比上下文中執行的操作
4: }
二、聲明式類比編程
如果你希望整個操作都在類比上下文中執行,你可以採用聲明式的類比編程。具體來說,你只需要在需要進行類比的服務作業方法上應用OperationBehaviorAttribute特性,並指定相應的類比選項即可。
1: [AttributeUsage(AttributeTargets.Method)]
2: public sealed class OperationBehaviorAttribute : Attribute, IOperationBehavior
3: {
4: //其他成員
5: public ImpersonationOption Impersonation { get; set; }
6: }
7: public enum ImpersonationOption
8: {
9: NotAllowed,
10: Allowed,
11: Required
12: }
通過OperationBehaviorAttribute的Impersonation屬性指定類比選項通過枚舉ImpersonationOption表示。定義在ImpersonationOption的三個枚舉項NotAllowed、Allowed和Required分別表示的含義如下。
- NotAllowed:不允許類比用戶端身份,這是預設值;
- Allowed:在身份類比條件滿足條件允許類比用戶端身份;
- Required:強制類比用戶端身份。這要求強制採用Windows認證,如果採用非Windows認證,會拋出異常。
此外,如果你要求服務的所有操作均強制採用身份類比,你可以通過編程或者配置將ServiceAuthorizationBehavior的ImpersonateCallerForAllOperations屬性設定成true。但是在這種情況下,如果該服務具有任何類比選項被設定成NotAllowed的服務作業,服務在寄宿過程中會拋出InvalidationOperationException異常。
1: public sealed class ServiceAuthorizationBehavior : IServiceBehavior
2: {
3: //其他成員
4: public bool ImpersonateCallerForAllOperations { get; set; }
5: }
三、設定類比層級
在採用Windows認證的情況下,服務可以在成功認證後可以擷取代表用戶端身份的WindowsIdentity對象。但是服務端是否可以根據WindowsIdentity擷取用戶端身份資訊,是否可以類比用戶端身份訪問某些安全資源,這取決於該WindowsIdentity的類比層級。
身份類比密切地關係到被類比身份代表的使用者的安全,所以類比層級應該通過用戶端自行控制。在WCF安全體系中,該類比層級是在用戶端提供的Windows憑證中指定。如下面的代碼所示,表示用戶端Windows憑證的WindowsClientCredential類型中,具有一個類型為TokenImpersonationLevel枚舉的AllowedImpersonationLevel屬性,用以指定類比層級。該屬性的預設值為None,實際上代表的等級是Identification。
1: public sealed class WindowsClientCredential
2: {
3: //其他成員
4: public TokenImpersonationLevel AllowedImpersonationLevel { get; set; }
5: }