HTTP Message Handler
html
在 Web Api 2 認證與受權 中講解了幾種實現機制,本篇就詳細講解 Message Handler 的實現方式git
關於 Message Handler 在 request 到 response 過程所處於的位置,能夠參考這裏 HTTP Message Handlersgithub
Authentication Message Handlerweb
先看一段實現的代碼,而後再作講解,完整代碼能夠在 Github 上參考,WebApi2.Authenticationjson
1 using System; 2 using System.Net; 3 using System.Net.Http; 4 using System.Security.Claims; 5 using System.Threading; 6 using System.Threading.Tasks; 7 // WebPrint.Framework reference https://github.com/LeafDuan/WebPrint/tree/master/WebPrint.Framework 8 using WebPrint.Framework; 9 10 namespace Server.Helper 11 { 12 // references 13 // http://www.codeproject.com/Articles/630986/Cross-Platform-Authentication-With-ASP-NET-Web-API 14 // http://dgandalf.github.io/WebApiTokenAuthBootstrap/ 15 public class AuthenticationMessageHandler : DelegatingHandler 16 { 17 protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, 18 CancellationToken cancellationToken) 19 { 20 if (request.Headers.Authorization == null) 21 { 22 var reply = request.CreateResponse(HttpStatusCode.Unauthorized, "Missing authorization token."); 23 24 return Task.FromResult(reply); 25 } 26 27 try 28 { 29 var encryptedToken = request.Headers.Authorization.Parameter; 30 var token = Token.Decrypt(encryptedToken); 31 //bool isValidUser 32 var isIpMathes = token.ClientIp.EqualTo(request.GetClinetIp()); 33 34 if (!isIpMathes) 35 { 36 var reply = request.CreateResponse(HttpStatusCode.Unauthorized, "Invalid authorization token"); 37 return Task.FromResult(reply); 38 } 39 40 var principal = new ClaimsPrincipal(new ClaimsIdentity(new[] 41 { 42 new Claim(ClaimTypes.Name, token.UserId.ToString()) 43 }, "Basic")); 44 45 // authorize attribute 46 request.GetRequestContext().Principal = principal; 47 } 48 catch (Exception ex) 49 { 50 var reply = request.CreateErrorResponse(HttpStatusCode.Unauthorized, ex.Message); 51 return Task.FromResult(reply); 52 } 53 54 return base.SendAsync(request, cancellationToken); 55 } 56 } 57 }
實現也是很簡單,經過繼承 DelegatingHandler 重寫 SendAsync 方法實現,整個流程須要的步驟以下:api
1 登陸,經過 api/auth 接收登陸信息,驗證後生成一個 tokenasp.net
2 每次請求判斷 request.Headers.Authorization 參數,看是否攜帶 token (Http Client 將步驟 1 中的 token 設置到 request.Headers.Authorization)ide
3 解析 token,設置請求上下文的 Principal 用於 Authorize 屬性使用oop
基本過程就差很少這三部曲,其中關於 token 的驗證,如是否超時,是否重複,可自行想辦法去實現spa
Web Api Config
你們都知道 Message Handler 在 pipeline 裏是在 controller 以前運行,所以請求全部的 Api Controller 都會先執行 handler,所以針對登陸,須要給予額外的照顧,容許匿名訪問,實現方法:handler 能夠是全局的,也能夠是 per router 的,所以此處經過後一種方式實現:
1 using System.Linq; 2 using System.Net.Http.Formatting; 3 using System.Web.Http; 4 using System.Web.Http.Dispatcher; 5 using Newtonsoft.Json; 6 using Server.Helper; 7 8 namespace Server 9 { 10 public static class WebApiConfig 11 { 12 public static void Register(HttpConfiguration config) 13 { 14 config.MapHttpAttributeRoutes(); 15 16 config.Routes.MapHttpRoute( 17 name: "Authentication", 18 routeTemplate: "api/auth", 19 defaults: new {controller = "account"} 20 ); 21 22 config.Routes.MapHttpRoute( 23 name: "DefaultApi", 24 routeTemplate: "api/{controller}/{id}", 25 defaults: new {id = RouteParameter.Optional}, 26 constraints: null, 27 handler: new AuthenticationMessageHandler {InnerHandler = new HttpControllerDispatcher(config)} 28 ); 29 30 var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First(); 31 32 jsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; 33 jsonFormatter.SerializerSettings.ContractResolver = new NHibernateContractResolver(); 34 } 35 } 36 }
總結
最近匆匆忙忙使用託管在 Owin Self Host 上的 Web Api 2,遇到問題頗多,不少也是匆匆忙忙解決的,這裏也就匆匆忙忙作一個分享。