Web Api 2 认证与授权 2

HTTP Message Handler

Web Api 2 认证与授权 中讲解了几种实现机制,本篇就详细讲解 Message Handler 的实现方式

关于 Message Handler 在 request 到 response 过程所处于的位置,可以参考这里 HTTP Message Handlers

 

Authentication Message Handler

先看一段实现的代码,然后再做讲解,完整代码可以在 Github 上参考,WebApi2.Authentication

 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 方法实现,整个流程需要的步骤如下:

1 登录,通过 api/auth 接收登录信息,验证后生成一个 token

2 每次请求判断  request.Headers.Authorization 参数,看是否携带 token (Http Client 将步骤 1 中的 token 设置到 request.Headers.Authorization)

3 解析 token,设置请求上下文的 Principal 用于 Authorize 属性使用

基本过程就差不多这三部曲,其中关于 token 的验证,如是否超时,是否重复,可自行想办法去实现

 

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,遇到问题颇多,很多也是匆匆忙忙解决的,这里也就匆匆忙忙做一个分享。

 

你可能感兴趣的:(Web)