代码改变世界

构建 Owin 中间件 来获取客户端IP地址

2017-11-21 13:47  Dorisoy  阅读(1091)  评论(0编辑  收藏  举报

Not so long ago, we discussed on this blog the possible ways of retrieving the client’s IP address in ASP.NET Web API.

With the latest changes in the Web API 2 infrastructure, and the emergence of Owin and the Katana project as the common glue between the underlying host and the web framework(s) running on it, it’s becoming natural to move these types of application-wide concerns (security, logging etc) to Owin middleware.

Let’s have a look at how you could – as an introductory example – obtain client’s IP address at the Owin middleware level, and why is it beneficial.

The benefits of Owin

We’ll not really go into the basic details of Owin here – I have already covered that in previous posts – so let’s just say that the gist is that with Owin we can easily host a number of frameworks side by side and decouple our web frameworks from the host beneath it. Naturally, through Owin middleware, we can address common concerns in a single place too – the most obvious usage being security.

If you are used to working with HttpMessageHandlers, the idea behind OWIN middleware is very similar – as they are chained one after another and allow you to modify the incoming request or outgoing response.

For quite a while, working with OWIN middleware meant dealing with quite a raw API, as you’d have to handle constructs such as Func<idictionary<string, object="">, Task>.

Now, Microsoft.Owin.dll provides a base abstract class for creating Owin middleware easily:

With that in place, it’s almost like implementing a MessageHandler.

Getting started with IP example

To get started we’ll need a new console project and following packages:

  • – Katana: install-package Microsoft.Owin.Hosting -pre
  • – Katana Http Listener: install-package Microsoft.Owin.Host.HttpListener -pre
  • – Web API adapter: install-package Microsoft.AspNet.WebApi.Owin -pre

These 3 packages will bring in some additional dependencies they have.
We can now start a simple Owin server with Web API host – this is nothing new and should be very straight forward.

So really just a simple Web API Test controller and a setup to wire it all together.

Adding Owin middleware for IP inspection

Now suppose you’d like to restrict specific IP addresses.

If we do it at Owin level, it would affect all the frameworks running in your process (perhaps you might want to add SignalR or NancyFx) – so sounds like a perfect place to do it, doesn’t it?

Well, it’s extremely easy. We simply inherit from OwinMiddleware class and implement the Invoke method.

In this case, we also pass in the list of restricted IPs. When we add our middleware to the pipeline, we are allowed to pass in params object[] so we can send whatever we want into our middleware constructor (more on that in a second).

We can retrieve the client’s IP address by asking for server.RemoteIpAddress key of the Environment object on the OwinRequest – it’s an IDictionary<string, object=""> and contains everything that could be interesting for us.

Based on that we can either deny the request (let’s say send a 403 Forbidden status code), otherwise we continue on to the next middleware.

To plug this in we need to add the following in the Configuration method of the Startup class – notice that this is the moment that we can send in any params to the Middleware too:

Also, we want to add it before the call to setup Web API!

Trying it out

Now if we access from a client that’s allowed to see the API, he gets the correct response as expected:

If the client is restricted, we reply with the 403 directly from the middleware: