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.
Types of Dependency Injection The injector class injects dependencies broadly in three ways: through a constructor, through a property, or through a method. Constructor Injection: In the constructor injection, the injector supplies the service (dependency) through the client class constructor.
Dependency injection (DI) is a technique widely used in programming and well suited to Android development. By following the principles of DI, you lay the groundwork for good app architecture. Implementing dependency injection provides you with the following advantages: Reusability of code.
ASP.NET Core supports the dependency injection (DI) software design pattern, which is a technique for achieving Inversion of Control (IoC) between classes and their dependencies. For more information specific to dependency injection within MVC controllers, see Dependency injection into controllers in ASP.NET Core.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With