WCF4.0 ¨C- RESTful WCF Services (4)
(Basic Security)
ÔÚREST¼Ü¹¹µÄWCF·þÎñÖУ¬Ëü²»ÏñÒ»°ãµÄWCF·þÎñ°ó¶¨£¬ÓÐÅäÌ׵ݲȫģʽ£¬ÊµÏÖÆðÀ´ÄÇô¼òµ¥¡£REST
WCF·þÎñÖ»ÄÜÔÚ´«Êä²ã¼ÓÃÜ£¬¶øÒ»°ãµÄWCF ·þÎñ¿ÉÒÔÔÚÏûÏ¢²ã¼ÓÃÜ¡£Òò´Ë REST WCF·þÎñÆôÓÃASP.NET¼æÈÝģʽºó£¬ËüµÄ°²È«ÊÇÓÉASP.NETÀ´±£Ö¤µÄ¡£±¾ÆªÎÄÕÂÖ÷Òª½éÉÜÔÚ
REST WCF ÖÐÈçºÎʵÏÖ×î¼òµ¥µÄ Username ÑéÖ¤¡£
ÔÚSOAPÐÒéµÄWCFÖУ¬¿ÉÒÔͨ¹ýSOAPHeader£¨MessageHeader)À´ÊµÏÖÓû§ÃûÃÜÂëµÄ´«Ê䣬ÔçÔÚWebServiceʱ´úÎÒÃǾÍÕâôÓùýÁË¡£ÔÚREST
WCFÖУ¬ÎÒÃÇ¿ÉÒÔÀûÓà HttpHeader À´Íê³ÉÕâһĿ±ê¡£ £¨Äã¿É²»»áÏëÔÚÿ¸ö·þÎñÆõÔ¼Àï¼ÓÉÏÓû§ºÍÃÜÂëµÄ²ÎÊý°É...)
Ê×ÏÈÔÚ·þÎñÖмÓÈëÈçÏ·½·¨ÓÃÓÚУÑ飬HeaderµÄÐÅÏ¢£ºÈç¹û Header ÖÐ Authorization
µÄ×Ö·û´®²»ÊÇ"fangxing/123" ÄÇô¾Í½«·µ»Ø 405 MethodNotAllowed
µÄ´íÎó¡£Õâ¸ö×Ö·û´®µÄÄÚÈÝ¿ÉÒÔ×Ô¶¨Ò壬·´Õý·þÎñ¶Ë¸ù¾ÝijÖÖ¹æÔò¼ì²éÕâ¸ö×Ö·û´®¡£
private bool CheckAuthorization() { var ctx = WebOperationContext.Current; var auth = ctx.IncomingRequest.Headers[HttpRequestHeader.Authorization]; if (string.IsNullOrEmpty(auth) || auth != "fangxing/123") { ctx.OutgoingResponse.StatusCode = HttpStatusCode.MethodNotAllowed; return false; } return true; } |
È»ºóÔÚÿһ¸ö·þÎñÆõÔ¼µÄʵÏÖÖУ¬¶¼È¥µ÷ÓÃËü¡£
[WebGet(UriTemplate = "All")] public List<Task> GetTask() { if (!CheckAuthorization()) return null; return GetData(); } [WebGet(UriTemplate = "{taskId}")] public Task GetTaskById(string taskId) { if (!CheckAuthorization()) return null; return GetData().FirstOrDefault(t => t.Id==taskId); }
|
ÏÖÔڵķþÎñ£¬Èç¹ûÖ±½Óͨ¹ýä¯ÀÀÆ÷·ÃÎÊ£¬½«µÃµ½ 405 MethodNotAllowed
µÄ´íÎó£º

¿Í»§¶ËÖ»ÒªÏàÓ¦µÄÑéÖ¤Ðżӵ½ RequestHeader ÖÐÈ¥£¬¾Í¿ÉÒÔ·ÃÎÊÁË¡£¿Í»§¶Ë¿ÉÒÔʹÓõ¥ÀýģʽÉè¼Æ
Client ¶ÔÏó¡£
ÕâÑù¾Í²»ÓÃÿ´Îµ÷Óö¼È¥¼ÓÑéÖ¤ÐÅÏ¢ÁË¡£
var url = "http://localhost:3433/TaskService/All"; var client = new HttpClient(); client.DefaultHeaders.Add("Authorization", "fangxing/123"); var resp = client.Get(url); |
ÕâÀïʹÓõÄÊÇ Microsoft.Http.HttpClient (WCF REST Starter
Kit) ¶ø·Ç System.Net.WebClient
»ØÍ·¿´·þÎñ¶Ë´úÂ룬ÿ¸ö·þÎñʵÏÖÖж¼ÐèÒª¼ÓÉÏ CheckAuthorization() ÊDz»ÊǺܷ³£¿
OK£¬ÎÒÃÇÖªµÀÕâ¸ö REST WCF·þÎñÊdzÐÔØÔÚÒ»¸öWeb ApplicationÉϵģ¬ ͨ¹ýÍù RouteTable
ÖÐ×¢²á WebServiceHostFactory À´¼¤»î·þÎñ¶ÔÏóµÄ¡£ ÄÇôֻҪ¶ÔÕâ¸ö WebServiceHostFactory
×öЩ¡°Êֽ𱣬¾Í¿ÉÒÔʵÏÖ·þÎñ¶ËÑéÖ¤µÄͳһÀ¹½Ø£¬´úÂëÈçÏ¡£(Ò»°ãµÄ WCF Ò²¿ÉÒÔÀûÓô˷½·¨¶Ô MessageHeader
½øÐÐÀ¹½ØÐ£Ñ飩
public class SecureWebServiceHostFactory : WebServiceHostFactory { protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses) { var host = base.CreateServiceHost(serviceType, baseAddresses); host.Authorization.ServiceAuthorizationManager = new MyServiceAuthorizationManager(); return host; } public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses) { var host = base.CreateServiceHost(constructorString, baseAddresses); host.Authorization.ServiceAuthorizationManager = new MyServiceAuthorizationManager(); return host; } } public class MyServiceAuthorizationManager : ServiceAuthorizationManager { protected override bool CheckAccessCore(OperationContext operationContext) { var ctx = WebOperationContext.Current; var auth = ctx.IncomingRequest.Headers[HttpRequestHeader.Authorization]; if (string.IsNullOrEmpty(auth) || auth != "fangxing/123") { ctx.OutgoingResponse.StatusCode = HttpStatusCode.MethodNotAllowed; return false; } return true; } } |
RegisterRoutes ÀïµÄ¹¤³§ÀàÒ²ÐèÒªÏàÓ¦µÄÐÞ¸ÄÏ£º
var securewebServiceHostFactory = new SecureWebServiceHostFactory(); RouteTable.Routes.Add(new ServiceRoute("TaskService", securewebServiceHostFactory, typeof(TaskService))); |
ÕâÑù·þÎñ¶Ë´úÂë¾Í¿ÉÒÔÈ¥µô CheckAuthorization() ¶ø°ÑÑéÖ¤¹¤×÷¶¼½»¸ø SecureWebServiceHostFactory
ÁË¡£
ÕâÖÖÑéÖ¤·½Ê½£¬ÆäʵҲÊÇÏÖÔÚ Windows Auzer Access Control µÄÔÐÍ¡£ Ö»²»¹ýÕâ¸ö
Authoriztion µÄ·þÎñÊÇרÃŵÄServices°ÕÁË¡£
1. ¿Í»§¶ËÏÈ´Ó·¢²¼ÁîÅÆµÄ·þÎñ»ñÈ¡ÁîÅÆ£»
2. ¿Í»§¶ËÄÃ×ÅÁîÅÆÌá½»µ½ÏÖÔڵķþÎñ£»
3.·þÎñ¶Ë½«¿Í»§¶ËÁîÅÆÄõ½·¢²¼ÁîÅÆµÄ·þÎñÉÏУÑé¡£

WCF4.0 ¨C- RESTful WCF Services (ʵÀý)
(²¢·¢Í¬²½·þÎñ SyncService)
×î½üд×Ô¶¯»¯²âÊÔʱÓöµ½Ò»¸öÎÊÌ⣺ ÎÒÃÇÔÚ½øÐÐÒ»¸ö²¢·¢²âÊԵĹý³ÌÖУ¬ÐèÒªËùÓпͻ§¶Ë²âÊÔ´úÂ룬ÔÚij¸öʱ»úͬ²½¡£»ØÏëËùѧµ½µÄ£¬Ïß³Ìͬ²½ÊֶκܶàÁË£¬Í¬Ò»Ì¨PCÉϵĽø³Ì¼äͬ²½Ò²¿ÉÒÔͨ¹ýMetuxʵÏÖ£¬¶àPCµÄʱºòÔõô°ì¡£ÒòΪ×î½üÔÚѧϰREST
WCF£¬×ÔÈ»Ïëµ½Ëü£¬ÓÃËüÀ´×ö¸öͬ²½·þÎñ£¬¼´¿ÉÒÔ½â¾ö¶àỊ̈߳¬¶à½ø³Ì£¬¶àPCͬ²½£¬»¹¿ÉÒÔÖ§³Ö¿çÓïÑÔ£¬ÕæÊÇÒ»¾Ù¶àµÃ¡£(ÀàËÆµÄ½â¾ö·½°¸»¹ÓÐPNUNIT£¬ËüÊÇͨ¹ý.Net
RemotingʵÏֵģ¬ÒòΪËü»¹ÒªÐ´ÅäÖ㬻¹ÒªÆðLancher/Agent£¬Óе㷳)¡£
1. SyncService µÄÖ÷Òª¹¦ÄÜ¡ª¡ªBarrier(À¸Õ¤)£º
½èÓÃPNUNITµÄ¸ÅÄîBarrier£¬Ò²¾ÍÊÇÒì²½¹ý³ÌÖеÄͬ²½µã£¬½øµ½BarrierÀïµÄËùÓжÔÏó¶¼ÒªµÈ´ýÆäËû¶ÔÏó½øÈë¡£ÕâЩ¶ÔÏó¿ÉÒÔÊDz»Í¬µÄỊ̈߳¬½ø³Ì(²»Í¬PC£¬²»Í¬ÓïÑÔʵÏֵĿͻ§¶Ë)£¬¹ý³ÌÈçÏÂͼ£º3¸ö¿Í»§¶ËÆô¶¯Ö®ºó£¬ÓпìÓÐÂý£¬µ«ÊÇÔÚBarrier´¦½øÐÐÒ»´Îͬ²½£¬Ïȵ½µÄµÈ´ýºóµ½µÄ¡£

¾Ù¸öʵ¼ÊÀý×Ó£º ¼ÙÈçÎÒÃÇҪʵÏÖÁ½¸ö¿Í»§¶ËͨÐŵŦÄܵIJâÊÔ£¬±ØÐëÊÇÁ½¸ö¿Í»§¶ËͬʱÉÏÏß¡£ÄÇôÎÒÃÇ¿ÉÒÔÔÚ´úÂëÖÐÉè¼ÆÒ»¸öbarrier£¬ÈÃË«·½¶¼È·ÈÏÉÏÏßÖ®ºó£¬ÔÙ½øÐÐͨÐŲâÊÔ¡£
(1) ×¼±¸Barrier
ÕâÀïÓеãÒªÌØ±ð˵Ã÷µÄµØ·½var init = SyncService.Init("Barrier_Logon", "Client1", "Client2"); // Æô¶¯Client1 Process.Start("Client1.exe"); // Æô¶¯Client2 Process.Start("Client2.exe"); |
(2) Client1
// client1µÇ¼ var client1 = Login("Client1"); // ͬ²½£¬µÈ´ýClient2µÇ¼ var enter = SyncService.Enter("Barrier_Logon", "Client1"); // client1 ºÍ client2 Ï໥ͨÐÅ ... |
(3) Client2 ºÍ Client1 ÀàËÆ
// client2µÇ¼ var client2 = Login("Client2"); // ͬ²½£¬µÈ´ýClient1µÇ¼ var enter = SyncService.Enter("Barrier_Logon", "Client2"); // client1 ºÍ client2 Ï໥ͨÐÅ ... |
2. SyncService µÄÏûÏ¢½»»»¹¦ÄÜ¡ª¡ªSetMessage/GetMessage£º
ÎÒÃÇ»¹¿ÉÒÔͨ¹ýSyncServiceÖеÄÏûÏ¢ÈÝÆ÷½øÐÐÏûÏ¢´«µÝ¡£ÈçÏÂͼ£º

ÔÚÒì²½µÄÁ½¶Î´úÂëÖУ¬ÉèÖÃͬ²½µã£¬±£Ö¤ GetMessage ÊÇÔÚ SetMessage Ö®ºó·¢Éú¡£ÕâÒ»µãÊDz¢ÐвâÊÔÖÐÊǺܳ£¼ûµÄ´¦Àí¡£
Client1µÄ´úÂ룺
// ÉèÖÃÏûÏ¢¸øclient2 var set = SyncService.SetMessage("Barrier", "key", "hello client2"); // ½øÈëBarrier, µÈ´ýclient2 var enter = SyncService.Enter("Barrier", "Client1"); |
Client2µÄ´úÂ룺
// ½øÈëBarrier,µÈ´ýclient1 var enter = SyncService.Enter("Barrier", "Client2"); // È¡µÃÏûÏ¢ var get = SyncService.GetMessage("Barrier", "key"); // È·ÈÏ»ñµÃÏûÏ¢£¬ÊÇ"hello client2" Assert.AreEqual(get, "hello client2"); |
3. SyncServiceµÄʵÏÖ
Èç¹ûÉÏÃæµÄ²¢Ðд¦Àí´úÂëÀí½âÁ˵ϰ£¬SyncServiceµÄʵÏ־ͺܺÃÍÆ¶Ï³öÀ´ÁË¡£·þÎñ¶Ëά»¤Ò»¸öDictionary<string,
SyncGroup>µÄÈÝÆ÷£¬Ã¿¸ö¿Í»§¶ËEnterʱ£¬µ÷ÓöÔÓ¦µÄManualResetEvent.Set()½âËø¡£È»ºóWaitAllÆäËûµÄManualResetEvent£¬´Ó¶øÊµÏÖͬ²½¡£

using System; using System.Collections.Generic; using System.Linq; using System.ServiceModel; using System.ServiceModel.Activation; using System.ServiceModel.Web; using System.Text; using System.Threading; using System.Runtime.Serialization; namespace SyncService { [ServiceContract] [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)] public class SyncService { private static Dictionary<string, SyncGroup> _syncPool = new Dictionary<string, SyncGroup>(); [WebGet(UriTemplate="Init/{barrier}/{targetnames}")] public string Init(string barrier, string targetnames) { var ctx = WebOperationContext.Current; try { lock (_syncPool) { _syncPool[barrier] = new SyncGroup(); var syncGroup = _syncPool[barrier]; var targets = targetnames.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); Array.ForEach(targets, t => syncGroup.ResetEventDict.Add(t, new ManualResetEvent(false))); } return "ok"; } catch (Exception ex) { return ex.Message; } } [WebGet(UriTemplate = "Enter/{barrier}/{targetname}/{timeout=60000}")] public string Enter(string barrier, string targetname, string timeout) { var ctx = WebOperationContext.Current; try { var syncObj = _syncPool[barrier]; var target = syncObj.ResetEventDict[targetname]; target.Set(); var intTimeout = int.Parse(timeout); var success = WaitHandle.WaitAll(syncObj.ResetEventDict.Values.ToArray(), intTimeout); if (success) return "ok"; else return "timeout"; } catch (Exception ex) { return ex.Message; } } [WebGet(UriTemplate = "SetMessage/{barrier}/{key}/{message=null}")] public string SetMessage(string barrier, string key, string message) { var ctx = WebOperationContext.Current; try { var syncObj = _syncPool[barrier]; lock (syncObj) { var query = syncObj.Messages.FirstOrDefault(m => m.Key == key); syncObj.Messages.Remove(query); var messageInfo = new MessageInfo { BarrierName = barrier, Key = key, Message = message, UpdateDateTime = DateTime.Now }; syncObj.Messages.Add(messageInfo); } return "ok"; } catch (Exception ex) { return ex.Message; } } [WebGet(UriTemplate = "GetMessage/{barrier}/{key}")] public string GetMessage(string barrier, string key) { var ctx = WebOperationContext.Current; try { var syncObj = _syncPool[barrier]; var query = syncObj.Messages.FirstOrDefault(m => m.Key == key); return query.Message; } catch (Exception ex) { return ex.Message; } } [WebGet(UriTemplate = "ListMessages/{barrier=all}", ResponseFormat=WebMessageFormat.Xml)] public List<MessageInfo> ListMessages(string barrier) { var ctx = WebOperationContext.Current; try { var messages = new List<MessageInfo>(); if (barrier == "all") _syncPool.Values.ToList().ForEach(t => messages.AddRange(t.Messages)); else messages = _syncPool[barrier].Messages; return messages; } catch { return null; } } [WebGet(UriTemplate="Check", ResponseFormat=WebMessageFormat.Xml)] public string Check() { return "Welcome to the SyncService! " + DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToLongTimeString(); } } [DataContract] [KnownType(typeof(MessageInfo))] public class SyncGroup { internal Dictionary<string, ManualResetEvent> ResetEventDict { get; set; } [DataMember] public string Name { get; set; } [DataMember] public List<MessageInfo> Messages { get; set; } [DataMember] public Dictionary<string, string> States { get; set; } public SyncGroup() { Messages = new List<MessageInfo>(); ResetEventDict = new Dictionary<string, ManualResetEvent>(); } } [DataContract] public class MessageInfo { [DataMember] public string BarrierName { get; set; } [DataMember] public string Key { get; set; } [DataMember] public string Message { get; set; } [DataMember] public string Identity { get; set; } [DataMember] public DateTime UpdateDateTime { get; set; } } } |
ĬÈÏʹÓÃJSON¸ñʽ£¬ÁíÍâΪÁ˲鿴µ±Ç°µÄͬ²½µÄ×´¿öºÍÏûÏ¢£¬¿ÉÒÔͨ¹ý ListStates/ListMessages
²é¿´¡£
(1) ³õʼ»¯BarrierÔò·¢ËÍ£º http://server/SyncService/Init/MyBarrier/Client1,Client2
(2) ¿Í»§¶Ë½øÈëBarrierÔò·¢ËÍ: http://server/SyncService/Enter/MyBarrier/Client1/10000
(×îºóÊÇtimeoutÉ趨)
(3) ÉèÖÃÏûÏ¢Ôò·¢ËÍ: http://server/SyncService/SetMessage/MyBarrier/Key/MessageContent
(4) È¡µÃÏûÏ¢Ôò·¢ËÍ: http://server/SyncService/GetMessage/MyBarrier/Key
(5) ²é¿´ËùÓеġ°Ëø¡±Ôò·¢ËÍ£ºhttp://server/SyncService/ListStates
(»òÕßÖ¸¶¨Ä³¸öBarrier: /MyBarrier)
(6) ²é¿´ËùÓеÄÏûÏ¢Ôò·¢ËÍ£ºhttp://server/SyncService/ListMessages(»òÕßÖ¸¶¨Ä³¸öBarrier:
/MyBarrier)
(7) Çå¿ÕËùÓÐSyncGroupÔò·¢ËÍ£ºhttp://server/SyncService/Restart
Êǵģ¬È«²¿µÄ²Ù×÷È«²¿ÊÇ HttpRequest µÄ"GET",
Òò´Ë¸÷ÖÖ¿Í»§¶Ë¶¼¿ÉÒÔÇáËɵ÷Ó㬺ܷ½±ã¡£ (ÓÃWCF´´½¨ÕâÑùÒ»¸ö·þÎñÒ²·Ç³£¼òµ¥È«²¿´úÂëÒ»°Ù¶àÐУ¬ÕýËùνÌìÏÂÎ书ÎÞ¿ì²»ÆÆ:)
ÉÏÆª:WCF4.0
¨C- RESTful WCF Services£¨Ò»£©
|