Reputation: 894
In my web api application I implemented OAuth2. On GrantResourceOwnerCredentials of ApplicationOAuthProvider I am calling my custom membership service to login and get the token.The problem is I have to inject the membership service into ApplicationOAuthProvider in order to use the service but it didn't allow it due to owinStartup class which don't support the parameter constructor.How do I inject/use my membership service in GrantResourceOwnerCredentials method.
public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
{
private readonly string _publicClientId;
private readonly IMembershipService _membershipService;
public ApplicationOAuthProvider(string publicClientId,
IMembershipService membershipService)
{
if (publicClientId == null)
{
throw new ArgumentNullException("publicClientId");
}
_publicClientId = publicClientId;
this._membershipService = membershipService;
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
AccountLogin LogCredentials = new AccountLogin();
LogCredentials.UserName = context.UserName;
LogCredentials.Password = context.Password;
ProviderLoginResponse providerLoginResponse =
_membershipService.UserLogin(LogCredentials);
if (providerLoginResponse.LoginStatus != "Y")
{
context.SetError("invalid_grant", "The user name or password
is incorrect.");
return;
}
var claims = new List<Claim>()
{
new Claim(ClaimTypes.Sid, Convert.ToString(1)),
new Claim(ClaimTypes.Name, providerLoginResponse.UserName),
new Claim(ClaimTypes.Email, providerLoginResponse.UserEmail)
};
ClaimsIdentity oAuthIdentity = new ClaimsIdentity(claims,
Startup.OAuthOptions.AuthenticationType);
AuthenticationProperties properties = CreateProperties(context.UserName);
AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
context.Validated(ticket);
}
}
My owin startup class :
public partial class Startup
{
private readonly IMembershipService _membershipService;
//This will cause a runtime error owin startup class only support parameterless constructor
public Startup(IMembershipService membershipService)
{
this._membershipService = membershipService;
}
public void ConfigureAuth(IAppBuilder app)
{
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
//Here passing the _membershipService to ApplicationOAuthProvider constructor
Provider = new ApplicationOAuthProvider(PublicClientId,_membershipService ),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
// In production mode set AllowInsecureHttp = false
AllowInsecureHttp = true
};
}
}
Upvotes: 3
Views: 5579
Reputation: 16801
One solution is to store the dependecy resolver as a static variable in, for example, the Startup.cs class and then resolve the interface against that.
As you tagged this question with MVC I'm guessing you have the Global.asax file along with the Startup.cs class. The Global.asax will be executed before the Startup.cs and that we can use in this solution.
In this solution I use Unity as container but you could use what ever you like.
Declare the static variable in Startup.cs class
public partial class Startup
{
public static UnityContainer IoC { get; set; }
...
Then in the WebApiConfig.Register() method, where the resolver is attached to the current HttpConfiguration, also set the variable in Startup.cs (Note that this will be called before the Startup.cs class)
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
var container = new UnityContainer();
//register all your interfaces in the container
container.RegisterType<IMembershipService, MembershipService>(new HierarchicalLifetimeManager());
Startup.IoC = container;
config.DependencyResolver = new UnityResolver(Startup.IoC);
}
}
Then use it in your Startup.cs
public partial class Startup
{
public static UnityContainer IoC { get; set; }
public void ConfigureAuth(IAppBuilder app)
{
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
//Resolve the interface here
Provider = new ApplicationOAuthProvider(PublicClientId, Startup.IoC.Resolve<IMembershipService>() ),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
// In production mode set AllowInsecureHttp = false
AllowInsecureHttp = true
};
}
}
Upvotes: 8