I’m currently using Unity with Unity.Mvc3 in my MVC3 application which uses Windows Authentication. I’m also reading up on doing dependency injection and am trying to set up an Ambient Context for some authorization checking.
I have an abstract AuthorizeContext class with a static property Current that holds one of three implementations of this class:
-
AuthorizeRoleContext, used for production, which takes a string and an IPrincipal through constructor injection and is just a layer of indirection to call IPrincipal.IsUserInRole whenever a request or demand for authorization is made. The injected string is used as a domain prefix for the role.
-
AuthorizeContextAllowAll, used for development and sometimes testing, which always allows all requests and demands for authorization, using a default constructor.
-
AuthorizeContextAllowNothing, used for testing minimum allowed functionality, which always denies all requests for authorization.
-
In the future, add one more and check authorization through a database…?
So I can manually wire things up by doing (for instance, in Application_BeginRequest):
AuthorizeContext.Current = new
AuthorizeRoleContext(HttpContext.Current.User);
and then call
AuthorizeContext.Current.Demand(“someRole”);
This works great, but I’m looking for the right way (and place) to wire it up with Unity, while avoiding the Service Locator anti-pattern. So my question is: how do I do this?
Some of the challenges I have with Unity registration so far:
- I do not have an HttpContext.Current.User at Application_Start, so I cannot inject it in AuthorizeRoleContext at that time
- I do not know how to assign an implementation to the static AuthorizeContext.Current property
Now maybe I should just do [Authorize(Roles = “Role1”)] everywhere and just let MVC3 do its thing, but:
- I also use it to build up my menu and perhaps want to use it in other places for authorization checking.
- I’d like to swap out authorization checking with other implementations (like allow all) so I don’t have to assign Windows Groups to each developer/tester.
- I seem to have to use a domain prefix for the role with IPrincipal.IsUserInRole or it won’t work across dev/test/production. Ofcourse, production is at the customer environment, using totally different domain names. This is the reason I made the domain name configurable and inject it.
- I’d like to unit test things.
But perhaps I’m still on the wrong track with this and I’m working around problems that aren’t there. 🙂
I’m not convinced that this extra layer of indirection adds any value. IPrincipal is already a polymorphic type, so you could accomplish exactly what you want in a much easier way.
Instead of AuthorizeRoleContext you could just use the IPrincipal provided by Windows Authentication (WindowsPrincipal).
Instead of AuthorizeContextAllowAll you could just implement IPrincipal like this:
Instead of AuthorizeContextAllowNothing implement IPrincipal like this:
To configure it, you could add this to Global.asax.cs:
To configure Unity with the ‘real’ IPrincipal, you can set it up like this:
To configure Unity with the AllowAllPrincipal is much easier:
and likewise with AllowNothingPrincipal:
If you must insist on wiring up your own AuthorizeContext, you could do so in a similar fashion.