[WCF許可權控制]利用WCF自定義授權模式提供當前Principal
在《原理篇》中我們談到:如果採用自定義安全主體許可權模式,我們可以透過自定義AuthorizationPolicy或者ServiceAuthorizationManager實現對基於當前認證用於相關的安全主體的提供,進而達到授權的目的。為了讓大家對此有個更加深刻的認識,在這篇文章中我們會提供一個具體的例子。[原始碼從這裡下載]
目錄:
一、建立自定義AuthorizationPolicy
二、建立自定義ServiceAuthorizationManager
三、透過自定義AuthorizationPolicy實現授權
四、透過自定義ServiceAuthorizationManager實現授權
一、建立自定義AuthorizationPolicy
我們先來演示透過自定義AuthorizationPolicy以提供當前安全主體的方式。我們透過自定義AuthorizationPolicy實現這樣的授權策略:如果使用者名稱為Foo(假設為管理員),我們建立一個包含“Administrators”角色的安全主體;而對於其他的使用者,提供的安全主體的角色列表中僅僅包括“Guest”。我們為該自定義AuthorizationPolicy起名為SimpleAdministrators,SimpleAdministrators整個定義如下。
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: }
這個安全主體的提供實現在Evaluate方法中,而其中唯一值得一提的是當前認證使用者名稱的獲取。在客戶端被成功認證之後,被認證的使用者實際上也透過某個宣告(Claim)儲存下來。該宣告的型別為“”,可以透過ClaimTypes的靜態屬性Name得到。而該Claim物件的Resource就是使用者名稱。在得到當前認證使用者名稱之後,相應的GenericPrincipal物件被建立出來,並被置於EvaluationContext的屬性列表中。並且該屬性對應的Key為“Principal”。
二、建立自定義ServiceAuthorizationManager
接下來我們來透過自定義ServiceAuthorizationManager來實現與上面完全一樣的功能,而已授權策略很簡單,我們照例將該自定義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不同的是,認證使用者的獲取在這裡變得更加容易,我們直接可以透過當前ServiceSecurityContext的PrimaryIdentity獲取。需要提醒一下的是,如果你在自定義AuthorizationPolicy的Evaluate方法中呼叫該屬性,會出現一個StackOverflowException異常,因為該屬性的呼叫本身又會觸發Evaluate方法的呼叫。最後被建立的GnericPrincipal被儲存在當前AuthorizationContext的屬性列表中,屬性的Key依然是“Principal”。
三、透過自定義AuthorizationPolicy實現授權
現在我們常見一個例項程式來應用我們建立的自定義AuthorizationPolicy,看看它是否能夠起到我們期望的授權的作用。我們依然沿用我們再熟悉不過的計算服務的例子,解決方案依然按照如下圖所示的結構來設計。整個解決方式包括四個專案:Contracts、Services、Hosting和Client。對於這樣的結構我們已經瞭解得夠多了,在這裡沒有必要再贅言敘述了。
在例項解決方案的整個結構建立之後,我們分別在Contracts和Services專案中定義服務契約介面和服務型別。下面是契約介面ICalculator和服務CalculatorService的定義。而在CalculatorService類的Add方法中應用了PrincipalPermissionAttribute特性,並將Roles屬性設定成了Adminstrators,意味著該服務操作只能被管理員使用者組中的使用者呼叫。
1: [ServiceContract(Namespace = "")]
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: }
現在透過Hosting這個控制檯程式對上面建立的服務進行寄宿。下面給出的是整個寄宿程式的配置,從中我們可以看出:應用到CalculatorService的服務行為列表中包含了PrincipalPermissionMode為Custom的ServiceAuthorizationBehavior。而我們定義的SimpleAuthorizationPolicy型別被配置到了
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
由於我們使用了WSHttpBinding,而它在預設的情況下采用Windows客戶端憑證,為此我們需要建立兩個Windows帳號Foo和Bar,密碼被設定為Password。在如下所示的客戶端程式碼中,我們分別以Foo和Bar的名義呼叫了服務。最後將服務能夠成功呼叫的結果列印出來。
1: class Program
2: {
3: static void Main(string[] args)
4: {
5: ChannelFactorychannelFactory = new ChannelFactory ("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("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("服務呼叫成功...");
27: }
28: catch (Exception ex)
29: {
30: Console.WriteLine("服務呼叫失敗...");
31: }
32: }
33: }
從下面的結果來看,只有在使用者名稱為Foo才能成功呼叫服務,而Bar由於許可權不足會導致服務呼叫失敗。這充分證明了透過自定義AuthorizationPolicy能夠正確地起到授權的作用。
1: 服務呼叫成功...
2: 服務呼叫失敗...
四、透過自定義ServiceAuthorizationManager實現授權
在證明我們自定義的AuthorizationPolicy確實能夠按照我們定義的策略進行授權之後,我們來試試我們自定義的ServiceAuthorizationManager能否同樣完成授權的使命。為此我們唯一需要做的就是改變一下服務寄宿程式的配置。
1:
2:
3:
4:
5:
6:
7: contract="Artech.WcfServices.Contracts.ICalculator"/>
8:
9:
10:
11:
12:
13:
14: serviceAuthorizationManagerType="Artech.WcfServices.Hosting.SimpleServiceAuthorizationManager,
15: Artech.WcfServices.Hosting" >
16: <!--
17:
18: -->
19:
20:
21:
22:
23:
24:
25:上面所示的採用自定義ServiceAuthorizationManager實現授權的配置。我們將之前新增的AuthorizationPolicy註釋掉,然後透過ServiceAuthorizationBehavior配置節的serviceAuthorizationManagerType屬性設定成我們自定義的SimpleServiceAuthorizationManager的型別。執行程式後,你會得到和上面一樣的輸出結果。
1: 服務呼叫成功...
2: 服務呼叫失敗...
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/1868/viewspace-2810181/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- [WCF許可權控制]透過擴充套件自行實現服務授權套件
- hadoop自定義許可權Hadoop
- Vue2-利用自定義指令實現按鈕許可權控制Vue
- android動態許可權到自定義許可權框架Android框架
- DRF內建許可權元件之自定義許可權管理類元件
- Django(63)drf許可權原始碼分析與自定義許可權Django原始碼
- 許可權控制
- Vue | 自定義指令和動態路由實現許可權控制Vue路由
- 如何用 Vue 實現前端許可權控制(路由許可權 + 檢視許可權 + 請求許可權)Vue前端路由
- 授權|取消授權MYSQL資料庫使用者許可權MySql資料庫
- shiro許可權控制
- SpringSecurity:hasAuthority與自定義許可權校驗SpringGse
- 授權許可權服務設計解析
- 基於VUE自定義指令實現按鈕級許可權控制Vue
- 許可權管理之多租戶隔離授權
- 為什麼許可權授權很難?- osohq
- 1.7.6. 授權和撤銷管理許可權
- Linux的許可權控制Linux
- django開發之許可權管理(一)——許可權管理詳解(許可權管理原理以及方案)、不使用許可權框架的原始授權方式詳解Django框架
- Think Authz:支援 ACL、RBAC、ABAC 等模型的授權(角色和許可權控制)庫模型
- 認證鑑權與API許可權控制在微服務架構中的設計與實現:授權碼模式API微服務架構模式
- Laravel實現許可權控制Laravel
- 安卓備份當前分割槽(需要root許可權)安卓
- 許可權維持專題:域控制器許可權維持
- 『學了就忘』Linux許可權管理 — 54、sudo授權Linux
- MongoDB4.0建立自定義許可權(只有查詢,插入和更新的許可權)的角色步驟MongoDB
- 造輪子之自定義授權策略
- Laravel 授權系統 - 自定義引數Laravel
- 許可權之選單許可權
- linux 檔案許可權 s 許可權和 t 許可權解析Linux
- 分享!! 如何自定義許可權校驗的註解並用AOP攔截實現許可權校驗
- 許可權控制及AOP日誌
- springboot-許可權控制shiro(二)Spring Boot
- etcd套路(四)auth許可權控制
- 資料分析的許可權控制
- Java 訪問許可權控制(6)Java訪問許可權
- vue-router控制路由許可權Vue路由
- Spring MVC 整合 Shiro 許可權控制SpringMVC