17

New to Dependency Injection, so this is probably a simple matter, but i have tried and cant figure it out, i am using Simple Injector.

I have a WebApi that uses SimpleInjector perfectly fine, now i would like to implement security using OAuth.

To do this i started to follow this tutorial, which is very helpful, but doesnt use Dependancy Injection

http://bitoftech.net/2014/06/01/token-based-authentication-asp-net-web-api-2-owin-asp-net-identity/

I have my global.asax file looking like this, to setup dependancy injection (working perfect)

protected void Application_Start()
{
    SimpleInjectorConfig.Register();

    GlobalConfiguration.Configure(WebApiConfig.Register);
}

I have created a Startup.Auth.cs file to configure OAuth

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        var OAuthServerOptions = new OAuthAuthorizationServerOptions()
        {
            AllowInsecureHttp = true,
            TokenEndpointPath = new PathString("/token"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
            Provider = new MyAuthorizationServerProvider() // here is the problem
        };

        // Token Generation
        app.UseOAuthAuthorizationServer(OAuthServerOptions);
        app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
    }
}

Now as i commented above, MyAuthorizationServerProvider is the problem. it takes a parameter of IUserService which i usually inject. I do not want to empty constructor because my IUserService also injects a repository. Here is the file

public class ApiAuthorizationServerProvider : OAuthAuthorizationServerProvider
{
    private IUserService _service;
    public ApiAuthorizationServerProvider (IUserService service) 
    {
         _service = service;
    }

    public override async Task ValidateClientAuthentication(
        OAuthValidateClientAuthenticationContext context)
    {
        context.Validated();
    }

    public override async Task GrantResourceOwnerCredentials(
        OAuthGrantResourceOwnerCredentialsContext context)
    {
        context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", 
            new[] { "*" });

        IUserService service = Startup.Container.GetInstance<IUserService>();
        User user = _service.Query(e => e.Email.Equals(context.UserName) &&
            e.Password.Equals(context.Password)).FirstOrDefault();

        if (user == null)
        {
            context.SetError("invalid_grant", 
                "The user name or password is incorrect.");
            return;
        }

        var identity = new ClaimsIdentity(context.Options.AuthenticationType);
        identity.AddClaim(new Claim("sub", context.UserName));
        identity.AddClaim(new Claim("role", "user"));

        context.Validated(identity);

    }
}

How can i get this working with Dependency Injection? This must happen quite a lot and must be able to do something to handle it. I am sure its something simple, but i am still learning.

Steven
  • 151,500
  • 20
  • 287
  • 393
Gillardo
  • 8,447
  • 14
  • 60
  • 126
  • 1
    Hope this helps https://simpleinjector.codeplex.com/discussions/564822 – DSR Sep 23 '14 at 14:25
  • did you find any other solution ? – moyomeh Feb 22 '16 at 17:15
  • I use OpenIddict from github and only store the role name as a claim. Permissions are not stored, because if something is updated, the change is immediate on the server. I only need to check permissions once per request, so this is fine for me atm – Gillardo Feb 22 '16 at 20:12

4 Answers4

24

I took some time to find out if it would be possible to register OAuthAuthorizationServerOptions in the Owin pipeling using the app.Use() method directly, instead of app.UseOAuthAuthorizationServer() which is just an extension method over app.Use(). app.Use() has an overload where you could register a delegate which you could use to construct the OAuthAuthorizationServerOptions.

Unfortunately this effort hit a dead end, because it seems that even if we'd use a delegate for the construction, this will be most likely only called once by the Owin pipeline which leads to the same result, namely a singleton instance of the OAuthAuthorizationServerOptions and thus all dependencies of this class will be singleton as well.

So the only solution to keep things working as they should be, is to pull a new instance of your UserService every time the GrantResourceOwnerCredentials() method is called.

But to follow the Simple Injector design principles it would be bad design to keep a dependency on the container in the ApiAuthorizationServerProvider class, like the original code shows.

A better way to do this would be to use a factory for the UserService class instead of directly pulling it from the container. The next code shows an example of how you could do this:

First of all, clean out the Application_Start() method in your global.asax file and place all your startup code in the Owin Startup() method. The code of the Startup() method:

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        var container = SimpleInjectorConfig.Register();

        GlobalConfiguration.Configure(WebApiConfig.Register);

        Func<IUserService> userServiceFactory = () => 
              container.GetInstance<IUserService>();

        var OAuthServerOptions = new OAuthAuthorizationServerOptions()
        {
            AllowInsecureHttp = true,
            TokenEndpointPath = new PathString("/token"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
            Provider = new ApiAuthorizationServerProvider(userServiceFactory)
        };

        // Token Generation
        app.UseOAuthAuthorizationServer(OAuthServerOptions);
        app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
    }
}

Notice how I changed the signature of the SimpleInjectorConfig.Register() function by returning the completly configured Simple Injector container to the caller so it can be used directly.

Now change the constructor of your ApiAuthorizationServerProvider class, so the factory method can be injected:

public class ApiAuthorizationServerProvider : OAuthAuthorizationServerProvider
{
    private Func<IUserService> userServiceFactory;

    public ApiAuthorizationServerProvider(Func<IUserService> userServiceFactory)
    {
        this.userServiceFactory = userServiceFactory;
    }

    // other code deleted for brevity...

    private IUserService userService 
    { 
        get
        {
            return this.userServiceFactory.Invoke();
        }
    }

    public override async Task GrantResourceOwnerCredentials(
        OAuthGrantResourceOwnerCredentialsContext context)
    {
        // other code deleted for brevity...
        // Just use the service like this
        User user = this.userService.Query(e => e.Email.Equals(context.UserName) &&
            e.Password.Equals(context.Password)).FirstOrDefault();

        // other code deleted for brevity...
    }
}

This way you get a new UserService everytime the GrantResourceOwnerCredentials() method is called and the complete dependency graph behind the UserService class will follow the lifetimes you defined in your Simple Injector configuration, while you depend on the container only in the composition root of the application.

Ric .Net
  • 5,440
  • 1
  • 17
  • 38
8

When you start with Dependency Injection, Owin is probably not the most friendly API to start with.

I noticed this part in your code:

IUserService service = Startup.Container.GetInstance<IUserService>();

You are probably doing this as a workaround before you find out how to use the constructor. But I think that's your answer right there. The OAuthAuthorizationServerProvider is a singleton, so your IUserService will be a singleton also and all the dependencies of this class will be singleton as well.

You mentioned you use a repository in your user service. Your probably don't want this repository to be singleton as I suppose this repository will use a DbContext of some kind.

So the intermediate answer could be the solution you made already. Maybe there is a more elegant solution if you do some research on what the UseOAuthAuthorizationServer method does exactly. The source code of Katana can be found here: Katana source code

For the registration of the other asp.net identity classes the link in the comment of DSR will give you a good starting point.

Ric .Net
  • 5,440
  • 1
  • 17
  • 38
  • Then i think i have misunderstood a previous answer. I adked this previously http://stackoverflow.com/questions/25997592/dependency-injection-using-simpleinjector-and-oauthauthorizationserverprovider and i guess the code above was not the answer? As i said i am new so not sure i understand ur answer? Can u explain a bit more please? – Gillardo Sep 23 '14 at 19:29
  • Are you sure the link is correct? It links to this post! The code I copied from your question is good intermediate solution as you ask the container for a new instance every time the 'GrantResourceOwnerCredentials' method is called. This is a good thing because otherwise there will be one and only one instance of your userservice during the complete lifetime of the application. – Ric .Net Sep 23 '14 at 19:38
  • Sorry i have got confused between 2 posts i have up on stackoverflow. I thought u replied to another post here http://stackoverflow.com/questions/26002866/unable-to-register-api-controller-using-simple-injector i have actually change this code on another post – Gillardo Sep 23 '14 at 19:48
  • The change in code in the other does not have an effect. The container.GetInstance method will be called only once. The instance that is created then will live for the lifetime of the application. Including the complete object graph behind this ApiAuthorizationServerProvider (UseService, repositories etc.). – Ric .Net Sep 24 '14 at 08:31
7

Firstly, this is a late answer. I just wrote this down in case somebody else come across the similar issue and somehow get linked to this page (like me) in the future.

The previous answer is reasonable, but will not solve the problem if the service is actually registered per Web API request, which I believe is what people usually do if they want to use dependency injection for identity framework object like UserManager.

The problem is when GrantResourceOwnerCredentials get called (usually when people hit the 'token' endpoint), simple injector won't start a api request life cycle. To solve this, all you need to do is start one.

public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    {
        //......
        using (Startup.Container.BeginExecutionContextScope())
        {
            var userService= Startup.Container.GetInstance<IUserService>();
            // do your things with userService..
        }
       //.....
    }

With BeginExecutionContextScope, simple injector will start a new context scope. However, remember it need to be disposed explicitly.

user3682091
  • 735
  • 1
  • 7
  • 16
  • 1
    This adds a dependency to the IoC framework. @Ric. Nets answer tries to hide this dependency, but doesn't solve the execution context scope problem. How to fix both problems? – mcanti Jan 15 '17 at 14:55
  • @mcanti theoretically I believe you can add middleware for the token endpoint to force a start of the API request life cycle, which I haven't try it myself, not sure if it will work or not. – user3682091 Jan 15 '17 at 23:20
0

As long as you are registering the dependency resolver for your webapi in your App_Start SimpleInjectorConfig.Register();

Like this

GlobalConfiguration.Configuration.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);

And if you are using the recommended AsyncScopedLifestyle Then you can use the dependency resolver to get a new instance of your services like this

using (var scope = System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver.BeginScope())
{
    var _userService = scope.GetService(typeof(IUserService)) as IUserService;
    //your code to use the service
}
Raiiy
  • 158
  • 1
  • 11