[WCF权限控制]利用WCF自定义授权模式提供当前Principal[实例篇]
在《原理篇》中我們談到:如果采用自定義安全主體權(quán)限模式,我們可以通過(guò)自定義AuthorizationPolicy或者ServiceAuthorizationManager實(shí)現(xiàn)對(duì)基于當(dāng)前認(rèn)證用于相關(guān)的安全主體的提供,進(jìn)而達(dá)到授權(quán)的目的。為了讓大家對(duì)此有個(gè)更加深刻的認(rèn)識(shí),在這篇文章中我們會(huì)提供一個(gè)具體的例子。[源代碼從這里下載]
目錄:
一、創(chuàng)建自定義AuthorizationPolicy
二、創(chuàng)建自定義ServiceAuthorizationManager
三、通過(guò)自定義AuthorizationPolicy實(shí)現(xiàn)授權(quán)
四、通過(guò)自定義ServiceAuthorizationManager實(shí)現(xiàn)授權(quán)
一、創(chuàng)建自定義AuthorizationPolicy
我們先來(lái)演示通過(guò)自定義AuthorizationPolicy以提供當(dāng)前安全主體的方式。我們通過(guò)自定義AuthorizationPolicy實(shí)現(xiàn)這樣的授權(quán)策略:如果用戶名為Foo(假設(shè)為管理員),我們創(chuàng)建一個(gè)包含“Administrators”角色的安全主體;而對(duì)于其他的用戶,提供的安全主體的角色列表中僅僅包括“Guest”。我們?yōu)樵撟远xAuthorizationPolicy起名為SimpleAdministrators,SimpleAdministrators整個(gè)定義如下。
1: public class SimpleAuthorizationPolicy : IAuthorizationPolicy 2: { 3: public SimpleAuthorizationPolicy() 4: { 5: this.Id = Guid.NewGuid().ToString(); 6: } 7: public bool Evaluate(EvaluationContext evaluationContext, ref object state) 8: { 9: string userName = string.Empty; 10: foreach (ClaimSet claimSet in evaluationContext.ClaimSets) 11: { 12: foreach (Claim claim in claimSet.FindClaims(ClaimTypes.Name, Rights.PossessProperty)) 13: { 14: userName = (string)claim.Resource; 15: } 16: } 17: 18: if (userName.Contains('\\')) 19: { 20: userName = userName.Split('\\')[1]; 21: } 22: evaluationContext.Properties["Principal"] = GetPrincipal(userName); 23: return false; 24: } 25:? 26: private IPrincipal GetPrincipal(string userName) 27: { 28: GenericIdentity identity = new GenericIdentity(userName); 29: if (string.Compare("Foo", userName, true) == 0) 30: { 31: return new GenericPrincipal(identity, new string[] { "Administrators" }); 32: } 33: return new GenericPrincipal(identity, new string[] {"Guest" }); 34: } 35:? 36: public ClaimSet Issuer 37: { 38: get { return ClaimSet.System; } 39: } 40: public string Id { get; private set; } 41: }這個(gè)安全主體的提供實(shí)現(xiàn)在Evaluate方法中,而其中唯一值得一提的是當(dāng)前認(rèn)證用戶名的獲取。在客戶端被成功認(rèn)證之后,被認(rèn)證的用戶實(shí)際上也通過(guò)某個(gè)聲明(Claim)保存下來(lái)。該聲明的類型為“http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name”,可以通過(guò)ClaimTypes的靜態(tài)屬性Name得到。而該Claim對(duì)象的Resource就是用戶名。在得到當(dāng)前認(rèn)證用戶名之后,相應(yīng)的GenericPrincipal對(duì)象被創(chuàng)建出來(lái),并被置于EvaluationContext的屬性列表中。并且該屬性對(duì)應(yīng)的Key為“Principal”。
二、創(chuàng)建自定義ServiceAuthorizationManager
接下來(lái)我們來(lái)通過(guò)自定義ServiceAuthorizationManager來(lái)實(shí)現(xiàn)與上面完全一樣的功能,而已授權(quán)策略很簡(jiǎn)單,我們照例將該自定義ServiceAuthorizationManager起名為SimpleServiceAuthorizationManager。以下是SimpleServiceAuthorizationManager的定義。
1: public class SimpleServiceAuthorizationManager : ServiceAuthorizationManager 2: { 3: protected override bool CheckAccessCore(OperationContext operationContext) 4: { 5: string userName = operationContext.ServiceSecurityContext.PrimaryIdentity.Name; 6: if (userName.Contains('\\')) 7: { 8: userName = userName.Split('\\')[1]; 9: } 10: operationContext.ServiceSecurityContext.AuthorizationContext.Properties["Principal"] = GetPrincipal(userName); 11: return true; 12: } 13: private IPrincipal GetPrincipal(string userName) 14: { 15: GenericIdentity identity = new GenericIdentity(userName); 16: if (string.Compare("Foo", userName, true) == 0) 17: { 18: return new GenericPrincipal(identity, new string[] { "Administrators"}); 19: } 20: return new GenericPrincipal(identity, new string[] { "Guest" }); 21: } 22: }和自定義AuthorizationPolicy不同的是,認(rèn)證用戶的獲取在這里變得更加容易,我們直接可以通過(guò)當(dāng)前ServiceSecurityContext的PrimaryIdentity獲取。需要提醒一下的是,如果你在自定義AuthorizationPolicy的Evaluate方法中調(diào)用該屬性,會(huì)出現(xiàn)一個(gè)StackOverflowException異常,因?yàn)樵搶傩缘恼{(diào)用本身又會(huì)觸發(fā)Evaluate方法的調(diào)用。最后被創(chuàng)建的GnericPrincipal被保存在當(dāng)前AuthorizationContext的屬性列表中,屬性的Key依然是“Principal”。
三、通過(guò)自定義AuthorizationPolicy實(shí)現(xiàn)授權(quán)
現(xiàn)在我們常見一個(gè)實(shí)例程序來(lái)應(yīng)用我們創(chuàng)建的自定義AuthorizationPolicy,看看它是否能夠起到我們期望的授權(quán)的作用。我們依然沿用我們?cè)偈煜げ贿^(guò)的計(jì)算服務(wù)的例子,解決方案依然按照如下圖所示的結(jié)構(gòu)來(lái)設(shè)計(jì)。整個(gè)解決方式包括四個(gè)項(xiàng)目:Contracts、Services、Hosting和Client。對(duì)于這樣的結(jié)構(gòu)我們已經(jīng)了解得夠多了,在這里沒有必要再贅言敘述了。
在實(shí)例解決方案的整個(gè)結(jié)構(gòu)建立之后,我們分別在Contracts和Services項(xiàng)目中定義服務(wù)契約接口和服務(wù)類型。下面是契約接口ICalculator和服務(wù)CalculatorService的定義。而在CalculatorService類的Add方法中應(yīng)用了PrincipalPermissionAttribute特性,并將Roles屬性設(shè)置成了Adminstrators,意味著該服務(wù)操作只能被管理員用戶組中的用戶調(diào)用。
1: [ServiceContract(Namespace = "http://www.artech.com/")] 2: public interface ICalculator 3: { 4: [OperationContract] 5: double Add(double x, double y); 6: } 7:? 8: public class CalculatorService : ICalculator 9: { 10: [PrincipalPermission(SecurityAction.Demand, Role = "Administrators")] 11: public double Add(double x, double y) 12: { 13: return x + y; 14: } 15: }現(xiàn)在通過(guò)Hosting這個(gè)控制臺(tái)程序?qū)ι厦鎰?chuàng)建的服務(wù)進(jìn)行寄宿。下面給出的是整個(gè)寄宿程序的配置,從中我們可以看出:應(yīng)用到CalculatorService的服務(wù)行為列表中包含了PrincipalPermissionMode為Custom的ServiceAuthorizationBehavior。而我們定義的SimpleAuthorizationPolicy類型被配置到了<authorizationPolicies>列表中。
1: <?xml version="1.0"?> 2: <configuration> 3: <system.serviceModel> 4: <services> 5: <service name="Artech.WcfServices.Services.CalculatorService" behaviorConfiguration="useCustomAuthorization"> 6: <endpoint address="http://127.0.0.1/calculatorservice" binding="ws2007HttpBinding" contract="Artech.WcfServices.Contracts.ICalculator"/> 7: </service> 8: </services> 9: <behaviors> 10: <serviceBehaviors> 11: <behavior name="useCustomAuthorization"> 12: <serviceAuthorization principalPermissionMode="Custom" > 13: <authorizationPolicies > 14: <add policyType="Artech.WcfServices.Hosting.SimpleAuthorizationPolicy, Artech.WcfServices.Hosting" /> 15: </authorizationPolicies> 16: </serviceAuthorization> 17: <serviceDebug includeExceptionDetailInFaults="true"/> 18: </behavior> 19: </serviceBehaviors> 20: </behaviors> 21: </system.serviceModel> 22: </configuration>由于我們使用了WSHttpBinding,而它在默認(rèn)的情況下采用Windows客戶端憑證,為此我們需要?jiǎng)?chuàng)建兩個(gè)Windows帳號(hào)Foo和Bar,密碼被設(shè)定為Password。在如下所示的客戶端代碼中,我們分別以Foo和Bar的名義調(diào)用了服務(wù)。最后將服務(wù)能夠成功調(diào)用的結(jié)果打印出來(lái)。
1: class Program 2: { 3: static void Main(string[] args) 4: { 5: ChannelFactory<ICalculator> channelFactory = new ChannelFactory<ICalculator>("calculatorService"); 6: NetworkCredential credential = channelFactory.Credentials.Windows.ClientCredential; 7: credential.UserName = "Foo"; 8: credential.Password = "Password"; 9: ICalculator calculator = channelFactory.CreateChannel(); 10: Invoke(calculator); 11:? 12: channelFactory = new ChannelFactory<ICalculator>("calculatorService"); 13: credential = channelFactory.Credentials.Windows.ClientCredential; 14: credential.UserName = "Bar"; 15: credential.Password = "Password"; 16: calculator = channelFactory.CreateChannel(); 17: Invoke(calculator); 18:? 19: Console.Read(); 20: } 21: static void Invoke(ICalculator calculator) 22: { 23: try 24: { 25: calculator.Add(1, 2); 26: Console.WriteLine("服務(wù)調(diào)用成功..."); 27: } 28: catch (Exception ex) 29: { 30: Console.WriteLine("服務(wù)調(diào)用失敗..."); 31: } 32: } 33: }從下面的結(jié)果來(lái)看,只有在用戶名為Foo才能成功調(diào)用服務(wù),而Bar由于權(quán)限不足會(huì)導(dǎo)致服務(wù)調(diào)用失敗。這充分證明了通過(guò)自定義AuthorizationPolicy能夠正確地起到授權(quán)的作用。
1: 服務(wù)調(diào)用成功... 2: 服務(wù)調(diào)用失敗...四、通過(guò)自定義ServiceAuthorizationManager實(shí)現(xiàn)授權(quán)
在證明我們自定義的AuthorizationPolicy確實(shí)能夠按照我們定義的策略進(jìn)行授權(quán)之后,我們來(lái)試試我們自定義的ServiceAuthorizationManager能否同樣完成授權(quán)的使命。為此我們唯一需要做的就是改變一下服務(wù)寄宿程序的配置。
1: <?xml version="1.0"?> 2: <configuration> 3: <system.serviceModel> 4: <services> 5: <service name="Artech.WcfServices.Services.CalculatorService" behaviorConfiguration="useCustomAuthorization"> 6: <endpoint address="http://127.0.0.1/calculatorservice" binding="ws2007HttpBinding" 7: contract="Artech.WcfServices.Contracts.ICalculator"/> 8: </service> 9: </services> 10: <behaviors> 11: <serviceBehaviors> 12: <behavior name="useCustomAuthorization"> 13: <serviceAuthorization principalPermissionMode="Custom" 14: serviceAuthorizationManagerType="Artech.WcfServices.Hosting.SimpleServiceAuthorizationManager, 15: Artech.WcfServices.Hosting" > 16: <!--<authorizationPolicies > 17: <add policyType="Artech.WcfServices.Hosting.SimpleAuthorizationPolicy, Artech.WcfServices.Hosting" /> 18: </authorizationPolicies>--> 19: </serviceAuthorization> 20: <serviceDebug includeExceptionDetailInFaults="true"/> 21: </behavior> 22: </serviceBehaviors> 23: </behaviors> 24: </system.serviceModel> 25: </configuration>上面所示的采用自定義ServiceAuthorizationManager實(shí)現(xiàn)授權(quán)的配置。我們將之前添加的AuthorizationPolicy注釋掉,然后通過(guò)ServiceAuthorizationBehavior配置節(jié)的serviceAuthorizationManagerType屬性設(shè)置成我們自定義的SimpleServiceAuthorizationManager的類型。運(yùn)行程序后,你會(huì)得到和上面一樣的輸出結(jié)果。
1: 服務(wù)調(diào)用成功... 2: 服務(wù)調(diào)用失敗...?
[WCF權(quán)限控制]利用WCF自定義授權(quán)模式提供當(dāng)前安全主體[原理篇]
[WCF權(quán)限控制]利用WCF自定義授權(quán)模式提供當(dāng)前安全主體[實(shí)例篇]
轉(zhuǎn)載于:https://www.cnblogs.com/artech/archive/2011/07/09/customauthorization02.html
總結(jié)
以上是生活随笔為你收集整理的[WCF权限控制]利用WCF自定义授权模式提供当前Principal[实例篇]的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: EnterpriseLibrary数据访
- 下一篇: ORA-00600: 内部错误代码,参数