问题
I am trying to setup a project structure so that I have a WebApi, WebUI and Domain layer. I have moved all the Asp.Net.Identity objects into the Domain layer and have also setup the ApplicationContext here too (inheriting from IdentityContext).
(I have used this tutorial and package as a base which is excellent. http://tech.trailmax.info/2014/09/aspnet-identity-and-ioc-container-registration/)
In the WebAPI layer I am able to use the Account controller correctly to login and register. However, I cannot generate an access token.
The OAuthGrantResourceOwnerCredentialsContext method internally uses
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
This works fine but doesnt give me the same context as my Account Controller as I am using Unity constructor injection in this to use my ApplicationUserManager from the domain.
I have tried injecting the OAuth class but I never seem to get the instance back.
Any advice?
Edit, this is what I have in Startup class in a default WebApi project.
// Configure the application for OAuth based flow
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
So the ApplicationOAuthProvider seems to be used when getting an access token.
-- More info.
UnityConfig.cs
container.RegisterType<ApplicationDbContext>(); //this is referencing my domain layer
Startup.Auth.cs
app.CreatePerOwinContext(() => DependencyResolver.Current.GetService<ApplicationUserManager>());
// Configure the application for OAuth based flow
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
ApplicationOAuthProvider.cs
Have injected constructor as below
public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
{
private readonly string _publicClientId;
private ApplicationUserManager userManager;
public ApplicationOAuthProvider(ApplicationUserManager userManager)
{
this.userManager = userManager;
}
public ApplicationOAuthProvider(string publicClientId)
{
//this.userManager = userManager;
if (publicClientId == null)
{
throw new ArgumentNullException("publicClientId");
}
_publicClientId = publicClientId;
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
//var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>(); //PROBLEM LINE!!!
ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
}
}
The problem line is shown above. This method gets called when requesting a token, and the userManager is always null.
Edit to show UnityWebApiActivator.cs
public static class UnityWebApiActivator
{
/// <summary>Integrates Unity when the application starts.</summary>
public static void Start()
{
// Use UnityHierarchicalDependencyResolver if you want to use a new child container for each IHttpController resolution.
// var resolver = new UnityHierarchicalDependencyResolver(UnityConfig.GetConfiguredContainer());
var resolver = new UnityDependencyResolver(UnityConfig.GetConfiguredContainer());
GlobalConfiguration.Configuration.DependencyResolver = resolver;
}
/// <summary>Disposes the Unity container when the application is shut down.</summary>
public static void Shutdown()
{
var container = UnityConfig.GetConfiguredContainer();
container.Dispose();
}
}
回答1:
I have just create pure WebApi project with Identity, checked over the classes and not sure I understand your question correctly.
The standard VS2013 template contains this in Startup.Auth.cs
:
public partial class Startup
{
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
public static string PublicClientId { get; private set; }
// For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
public void ConfigureAuth(IAppBuilder app)
{
// blah - other stuff
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
Provider = new ApplicationOAuthProvider(PublicClientId),
// another blah
};
app.UseOAuthBearerTokens(OAuthOptions);
//blah-blah-blah
}
}
I have checked and ApplicationOAuthProvider
is not used anywhere else. So no need to inject it.
Inside of this class, as you say, it calls for context.OwinContext.GetUserManager<ApplicationUserManager>()
to get user manager. If you get an incorrect instance of ApplicationDbContext
there, then you inject incorrect instance of ApplicationUserManager
into Owin context. Do you still have a line with this:
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
Go replace it with this:
app.CreatePerOwinContext(() => DependencyResolver.Current.GetService<ApplicationUserManager>());
This should do the job - would be the best solution.
Alternatively in ApplicationOAuthProvider
replace line where you get the ApplicationUserManager
from OWIN context with this:
var userManager = DependencyResolver.Current.GetService<ApplicationUserManager>()
This should resolve your user manager from Unity, giving you correct DbContext
.
来源:https://stackoverflow.com/questions/27041112/asp-net-identity-generate-webapi-token-oauthgrantresourceownercredentialscontex