Autofac dependency injection in implementation of OAuthAuthorizationServerProvider
我正在创建一个Web API应用程序,我想使用承载令牌进行用户身份验证。我实现了令牌逻辑,遵循这个帖子,一切看起来都很好。注意:我没有使用ASP.NET标识提供程序。相反,我为它创建了一个自定义用户实体和服务。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | public class Startup { public void Configuration(IAppBuilder app) { ConfigureOAuth(app); var config = new HttpConfiguration(); var container = DependancyConfig.Register(); var dependencyResolver = new AutofacWebApiDependencyResolver(container); config.DependencyResolver = dependencyResolver; app.UseAutofacMiddleware(container); app.UseAutofacWebApi(config); WebApiConfig.Register(config); app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll); app.UseWebApi(config); } public void ConfigureOAuth(IAppBuilder app) { var oAuthServerOptions = new OAuthAuthorizationServerOptions { AllowInsecureHttp = true, TokenEndpointPath = new PathString("/token"), AccessTokenExpireTimeSpan = TimeSpan.FromDays(1), Provider = new SimpleAuthorizationServerProvider() }; // Token Generation app.UseOAuthAuthorizationServer(oAuthServerOptions); app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()); } } |
这是SimpleAuthorizationServerProvider类的实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | private IUserService _userService; public IUserService UserService { get { return (IUserService)(_userService ?? GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IUserService))); } set { _userService = value; } } public async override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) { context.Validated(); } public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) { context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] {"*" }); var user = await UserService.GetUserByEmailAndPassword(context.UserName, context.Password); 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); } } |
调用/token url后,我收到以下错误
No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested. This generally indicates that a component registered as per-HTTP request is being requested by a SingleInstance() component (or a similar scenario.) Under the web integration always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime, never from the container itself
在这个类中有没有使用依赖注入的方法?我正在使用存储库模式来访问我的实体,因此我不认为创建对象上下文的新实例是一个好主意。正确的方法是什么?
我也遇到过类似的问题。
这里的问题是,当您尝试在您的供应商中注入
建议的解决方案是将依赖项注册为
经过更深入的调查,我解决了从
1 2 3 4 5 6 7 8 9 10 | using Autofac.Integration.Owin; ... public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) { ... // autofacLifetimeScope is 'AutofacWebRequest' var autofacLifetimeScope = OwinContextExtensions.GetAutofacLifetimeScope(context.OwinContext); var userService = autofacLifetimeScope.Resolve<IUserService>(); ... } |
我在
编辑
@Bramvandenbussche,这是我在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public void Configuration(IAppBuilder app) { // Configure Autofac var container = ConfigureAutofac(app); // Configure CORS ConfigureCors(app); // Configure Auth ConfigureAuth(app, container); // Configure Web Api ConfigureWebApi(app, container); } |
要在
1 2 3 4 5 | builder .RegisterType<SimpleAuthorizationServerProvider>() .As<IOAuthAuthorizationServerProvider>() .PropertiesAutowired() // to automatically resolve IUserService .SingleInstance(); // you only need one instance of this provider |
您还需要将容器传递给
1 2 3 4 5 6 7 | var oAuthServerOptions = new OAuthAuthorizationServerOptions { AllowInsecureHttp = true, TokenEndpointPath = new PathString("/token"), AccessTokenExpireTimeSpan = TimeSpan.FromDays(1), Provider = container.Resolve<IOAuthAuthorizationServerProvider>() }; |
如果对象中的属性没有通过外部数据更改,则应始终使用单个实例(例如,您在控制器中设置了一个属性,该属性依赖于数据库中存储的某些信息,在这种情况下,应使用InstancePerRequest)。
我还尝试使用owInContextExtensions.getAutoFacLifeTimeScope来回答@jumuro,这样可以节省一天的时间。不是在运行时注册iuserservice,而是在请求后验证/创建实例服务。
我添加了一些新的答案,因为我还不能发表评论,因为我的名声不好,但添加了额外的指南代码来帮助某人。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) { try { if (service == null) { var scope = Autofac.Integration.Owin.OwinContextExtensions.GetAutofacLifetimeScope(context.OwinContext); service = scope.Resolve<IUserService>(); } var user = await service.FindUserAsync(context.UserName); if (user?.HashedPassword != Helpers.CustomPasswordHasher.GetHashedPassword(context.Password, user?.Salt)) { context.SetError("invalid_grant","The user name or password is incorrect."); return; } } catch(Exception ex) { context.SetError("invalid_grant", ex.Message); return; } var identity = new ClaimsIdentity(context.Options.AuthenticationType); identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName)); AuthenticationProperties properties = CreateProperties(context.UserName); AuthenticationTicket ticket = new AuthenticationTicket(identity, properties); context.Validated(ticket); context.Request.Context.Authentication.SignIn(identity); } |