C# 使用ASP.Identity表将Autofac转换为ASP.NET WEPAPI 2.2
基于此,我编写了两个非常受支持的WebAPI。现在的问题是,我还没有对IoC/DI的需求,但我正在编写一个Web API,并试图从头开始将其合并 我对存储库/服务/工作单元模式有很好的处理能力,但在移植其中的标识部分时会出错。特别是在启动时使用OAuthConfiguration类,如下所示: 错误C# 使用ASP.Identity表将Autofac转换为ASP.NET WEPAPI 2.2,c#,asp.net-web-api,autofac,asp.net-identity-2,C#,Asp.net Web Api,Autofac,Asp.net Identity 2,基于此,我编写了两个非常受支持的WebAPI。现在的问题是,我还没有对IoC/DI的需求,但我正在编写一个Web API,并试图从头开始将其合并 我对存储库/服务/工作单元模式有很好的处理能力,但在移植其中的标识部分时会出错。特别是在启动时使用OAuthConfiguration类,如下所示: 错误 None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' o
None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'Vender.Providers.AuthorizationServerProvider' can be invoked with the available services and parameters:
Cannot resolve parameter 'Vender.Services.ApplicationClientService appClientsService' of constructor 'Void .ctor(Vender.Services.ApplicationClientService, Vender.Data.Context.ApplicationUserManager)'.
private static IContainer RegisterServices(ContainerBuilder builder)
{
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// EF HomeCinemaContext
builder.RegisterType < ApplicationDbContext>()
.As<DbContext>()
.InstancePerRequest();
builder.RegisterType<DbFactory>()
.As<IDbFactory>()
.InstancePerRequest();
builder.RegisterType<UnitOfWork>()
.As<IUnitOfWork>()
.InstancePerRequest();
builder.RegisterGeneric(typeof(EntityBaseRepository<>))
.As(typeof(IEntityBaseRepository<>))
.InstancePerRequest();
builder.RegisterType<ApplicationUserManager>()
.SingleInstance();
builder.RegisterType<AddressService>()
.As<IAddressService>()
.InstancePerRequest();
builder.RegisterType<ApplicationClientService>()
.As<IApplicationClientService>()
.InstancePerRequest();
builder.RegisterType<RefreshTokenService>()
.As<IRefreshTokenService>()
.InstancePerRequest();
builder.RegisterType<AuthorizationServerProvider>()
.AsImplementedInterfaces<IOAuthAuthorizationServerProvider, ConcreteReflectionActivatorData>().SingleInstance();
builder.RegisterType<RefreshTokenProvider>()
.AsImplementedInterfaces<IAuthenticationTokenProvider, ConcreteReflectionActivatorData>().SingleInstance();
Container = builder.Build();
return Container;
}
方法,但有异常(在尝试解析这两个提供程序时会出现上述错误)
publicstaticvoidconfigtokengeneration(IAppBuilder应用程序,IContainer容器)
{
app.CreatePerOwinContext(ApplicationDbContext.Create);
var oAuthServerOptions=新的OAuthAuthorizationServerOptions()
{
AllowInsecureHttp=ApiSettings.AllowInsecureHttp,
TokenEndpointPath=新路径字符串(“/token”),
AccessTokenExpireTimeSpan=TimeSpan.FromMinutes(ApiSettings.AccessTokenValidTime),
Provider=container.Resolve(),
AccessTokenFormat=新的JwtFormatProvider(ApiSettings.ApiAddress),
RefreshTokenProvider=container.Resolve()
};
使用OAuthAuthorizationServer(oAuthServerOptions);
}
有例外的类
public class AuthorizationServerProvider : OAuthAuthorizationServerProvider
{
private readonly ApplicationClientService _appClientsService;
private readonly ApplicationUserManager _userManager;
public AuthorizationServerProvider(ApplicationClientService appClientsService,
ApplicationUserManager userManager)
{
_appClientsService = appClientsService;
_userManager = userManager;
}
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
string clientId;
string clientSecret;
if (!context.TryGetBasicCredentials(out clientId, out clientSecret))
{
context.TryGetFormCredentials(out clientId, out clientSecret);
}
if (context.ClientId == null)
{
//Remove the comments from the below line context.SetError, and invalidate context
//if you want to force sending clientId/secrets once obtain access tokens.
context.Validated();
context.SetError("invalid_clientId", "ClientId should be sent.");
return Task.FromResult<object>(null);
}
var client = _appClientsService.FindApplicationClient(context.ClientId);
if (client == null)
{
context.SetError("invalid_clientId", $"Client '{context.ClientId}' is not registered in the system.");
return Task.FromResult<object>(null);
}
if (client.ApplicationType == ApplicationTypes.NativeConfidential)
{
if (string.IsNullOrWhiteSpace(clientSecret))
{
context.SetError("invalid_clientId", "Client secret should be sent.");
return Task.FromResult<object>(null);
}
else
{
if (client.Secret != Hash.FromString(clientSecret))
{
context.SetError("invalid_clientId", "Client secret is invalid.");
return Task.FromResult<object>(null);
}
}
}
if (!client.Active)
{
context.SetError("invalid_clientId", "Client is inactive.");
return Task.FromResult<object>(null);
}
context.OwinContext.Set<string>("as:clientAllowedOrigin", client.AllowedOrigin);
context.OwinContext.Set<string>("as:clientRefreshTokenLifeTime", client.RefreshTokenLifeTime.ToString());
context.Validated();
return Task.FromResult<object>(null);
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var allowedOrigin = context.OwinContext.Get<string>("as:clientAllowedOrigin") ?? "*";
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin });
IDictionary<string, string> userData = new Dictionary<string, string>();
var user = await _userManager.FindAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "apiError.invalidUsernameOrPassword");
return;
}
var oAuthIdentity = await user.GenerateUserIdentityAsync(_userManager, "JWT");
var userProps = new AuthenticationProperties(userData);
var ticket = new AuthenticationTicket(oAuthIdentity, userProps);
context.Validated(ticket);
/*
// Get userManager to test credentials against
//
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
// find user by username first
ApplicationUser user = await userManager.FindByEmailAsync(context.UserName);
if (user != null)
{
var validCredentials = await userManager.FindAsync(context.UserName, context.Password);
if (await userManager.IsLockedOutAsync(user.Id))
{
context.SetError("invalid_grant", "This account has been locked out. Please come back later.");
return;
}
else if (await userManager.GetLockoutEnabledAsync(user.Id) && validCredentials == null)
{
// Record the failure which also may cause the user to be locked out
await userManager.AccessFailedAsync(user.Id);
string message;
if (await userManager.IsLockedOutAsync(user.Id))
{
message = "apiError.accountLockout";
}
else
{
int accessFailedCount = await userManager.GetAccessFailedCountAsync(user.Id);
int attemptsLeft = Convert.ToInt32(ConfigurationManager.AppSettings["MaxFailedAccessAttemptsBeforeLockout"].ToString()) - accessFailedCount;
message = string.Format("apiError.lockoutAttempts{0}", attemptsLeft);
}
context.SetError("invalid_grant", message);
return;
}
else if (validCredentials == null)
{
context.SetError("invalid_grant", "Invalid username or password, please try again.");
return;
}
else
{
if (!user.EmailConfirmed)
{
context.SetError("invalid_grant", "Email has not yet been confirmed.");
return;
}
user.LastLoginDateUtc = System.DateTime.UtcNow;
user.SuccessLoginCount++;
var loginInfo = new LoginTracker();
loginInfo.ApplicationUser = user;
loginInfo.LoginTimeUtc = DateTime.UtcNow;
}
}
else
{
context.SetError("invalid_grant", "Invalid username or password, please try again.");
return;
}
*/
}
public override Task TokenEndpoint(OAuthTokenEndpointContext context)
{
foreach (KeyValuePair<string, string> property in context.Properties.Dictionary)
{
context.AdditionalResponseParameters.Add(property.Key, property.Value);
}
return Task.FromResult<object>(null);
}
}
公共类授权服务器提供程序:OAuthAuthorizationServerProvider
{
专用只读应用程序客户端服务(AppClientService);
专用只读应用程序userManager\u userManager;
公共授权服务器提供程序(ApplicationClient服务AppClientService,
ApplicationUserManager(用户管理器)
{
_appClientsService=appClientsService;
_userManager=userManager;
}
公共覆盖任务ValidateClientAuthentication(OAuthValidateClientAuthenticationContext)
{
字符串clientId;
字符串clientSecret;
if(!context.TryGetBasicCredentials(out-clientId,out-clientSecret))
{
TryGetFormCredentials(out clientId,out clientSecret);
}
if(context.ClientId==null)
{
//从下面的context.SetError行中删除注释,并使上下文无效
//如果要在获取访问令牌后强制发送clientId/secrets。
context.Validated();
SetError(“无效的clientId”,“应该发送clientId”);
返回Task.FromResult(空);
}
var client=_appClientsService.FindApplicationClient(context.ClientId);
if(客户端==null)
{
SetError(“无效的_clientId”,“未在系统中注册$”客户端“{context.clientId}”);
返回Task.FromResult(空);
}
if(client.ApplicationType==ApplicationTypes.nativeconfig)
{
if(string.IsNullOrWhiteSpace(clientSecret))
{
SetError(“无效的客户端ID”,“应发送客户端密码”);
返回Task.FromResult(空);
}
其他的
{
if(client.Secret!=Hash.FromString(clientSecret))
{
SetError(“无效的客户端ID”,“客户端密码无效”);
返回Task.FromResult(空);
}
}
}
如果(!client.Active)
{
SetError(“无效的客户端ID”,“客户端处于非活动状态”);
返回Task.FromResult(空);
}
context.OwinContext.Set(“as:clientAllowedOrigin”,client.AllowedOrigin);
context.OwinContext.Set(“as:clientRefreshTokenLifeTime”,client.RefreshTokenLifeTime.ToString());
context.Validated();
返回Task.FromResult(空);
}
公共重写异步任务GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentials上下文)
{
var allowedOrigin=context.OwinContext.Get(“as:clientAllowedOrigin”)??“*”;
context.OwinContext.Response.Headers.Add(“访问控制允许源代码”,new[]{allowedOrigin});
IDictionary userData=新字典();
var user=await\u userManager.FindAsync(context.UserName,context.Password);
if(user==null)
{
SetError(“无效的授权”,“APIRROR.InvalidUserName或密码”);
返回;
}
var oAuthIdentity=await user.GenerateUserIdentityAsync(_userManager,“JWT”);
var userProps=新的AuthenticationProperties(userData);
var票证=新的身份验证票证(oAuthIdentity,userProps);
上下文。已验证(票证);
/*
//获取userManager以测试凭据
//
var userManager=context.OwinContext.GetUserManager();
//首先按用户名查找用户
ApplicationUser=await userManager.findbyemailsync(context.UserName);
如果(用户!=null)
{
var validCredentials=await userManager.FindAsync(context.UserName,context.Password);
if(等待userManager.IsLockedOutAsync(user.Id))
{
SetError(“无效的授权”,“此帐户已被锁定。请稍后再来。”);
返回;
}
else if(等待userManager.GetLockoutEnabledAsync(user.Id)&&validCredentials==null)
{
//记录可能导致用户被锁定的故障
等待userManager.AccessFailedAsync(user.Id);
字符串消息;
if(等待userManager.IsLockedOutAsync(user.Id))
{
message=“apierro.accountlocket”;
}
其他的
{
int accessFailedCount=await userManager.GetAccessFailedCountAsync(user.Id);
private static IContainer RegisterServices(ContainerBuilder builder)
{
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// EF HomeCinemaContext
builder.RegisterType < ApplicationDbContext>()
.As<DbContext>()
.InstancePerRequest();
builder.RegisterType<DbFactory>()
.As<IDbFactory>()
.InstancePerRequest();
builder.RegisterType<UnitOfWork>()
.As<IUnitOfWork>()
.InstancePerRequest();
builder.RegisterGeneric(typeof(EntityBaseRepository<>))
.As(typeof(IEntityBaseRepository<>))
.InstancePerRequest();
builder.RegisterType<ApplicationUserManager>()
.SingleInstance();
builder.RegisterType<AddressService>()
.As<IAddressService>()
.InstancePerRequest();
builder.RegisterType<ApplicationClientService>()
.As<IApplicationClientService>()
.InstancePerRequest();
builder.RegisterType<RefreshTokenService>()
.As<IRefreshTokenService>()
.InstancePerRequest();
builder.RegisterType<AuthorizationServerProvider>()
.AsImplementedInterfaces<IOAuthAuthorizationServerProvider, ConcreteReflectionActivatorData>().SingleInstance();
builder.RegisterType<RefreshTokenProvider>()
.AsImplementedInterfaces<IAuthenticationTokenProvider, ConcreteReflectionActivatorData>().SingleInstance();
Container = builder.Build();
return Container;
}
public class ApplicationUserManager : UserManager<ApplicationUser>
{
public ApplicationUserManager(ApplicationDbContext identityContext)
: base(new UserStore<ApplicationUser>(identityContext))
{
}
public ApplicationUserManager(IUserStore<ApplicationUser> store, IDataProtectionProvider dataProtectionProvider)
: base(store)
{
UserValidator = new UserValidator<ApplicationUser>(this)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = true
};
// Configure validation logic for passwords
PasswordValidator = new PasswordValidator
{
RequiredLength = 6,
RequireNonLetterOrDigit = false,
RequireDigit = true,
RequireLowercase = true,
RequireUppercase = true,
};
// Configure user lockout defaults
UserLockoutEnabledByDefault = false;
//DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
//MaxFailedAccessAttemptsBeforeLockout = 5;
// Register two factor authentication providers. This application uses Phone and Emails as a step of receiving a code for verifying the user
// You can write your own provider and plug it in here.
RegisterTwoFactorProvider("Phone Code", new PhoneNumberTokenProvider<ApplicationUser>
{
MessageFormat = "Your security code is {0}"
});
RegisterTwoFactorProvider("Email Code", new EmailTokenProvider<ApplicationUser>
{
Subject = "Security Code",
BodyFormat = "Your security code is {0}"
});
UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"));
}
}
public class ApplicationClientService : IApplicationClientService
{
private readonly IEntityBaseRepository<ApplicationClient> _appClientRepository;
private readonly IUnitOfWork _unitOfWork;
public ApplicationClientService(IEntityBaseRepository<ApplicationClient> appClientRepository,
IUnitOfWork unitOfWork)
{
_appClientRepository = appClientRepository;
_unitOfWork = unitOfWork;
}
public async Task<bool> CreateApplicationClientAsync(ApplicationClient newToken)
{
_appClientRepository.Add(newToken);
return await _unitOfWork.CommitAsync() > 0;
}
public Task<ApplicationClient> FindApplicationClientAsync(string clientId)
{
var refreshToken = _appClientRepository.GetAll().FirstOrDefault(x => x.ClientId == clientId);
return Task.FromResult(refreshToken);
}
public ApplicationClient FindApplicationClient(string clientId)
{
var refreshToken = _appClientRepository.GetAll().FirstOrDefault(x => x.ClientId == clientId);
return refreshToken;
}
}
public interface IApplicationClientService
{
Task<bool> CreateApplicationClientAsync(ApplicationClient newToken);
ApplicationClient FindApplicationClient(string clientId);
}
var builder = new ContainerBuilder();
var config = GlobalConfiguration.Configuration;
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().SingleInstance();
builder.RegisterType<DbFactory>().As<IDbFactory>().SingleInstance();
builder.RegisterType<ApplicationDbContext>().AsSelf().SingleInstance();
// rest of code as singleInstance
builder.Register<IdentityFactoryOptions<ApplicationUserManager>>(c => new IdentityFactoryOptions<ApplicationUserManager>() { DataProtectionProvider = new DpapiDataProtectionProvider("Elhag.WebAPI") });
builder.RegisterType<ApplicationUserManager>().AsSelf().SingleInstance();
builder.Register(c=>new AuthorizationServerProvider(c.Resolve<ApplicationUserManager>())).AsImplementedInterfaces().SingleInstance();
builder.Register(c => new UserStore<ApplictionUser>(c.Resolve<ApplicationDbContext>())).AsImplementedInterfaces().SingleInstance();
builder.Register(c => HttpContext.Current.GetOwinContext().Authentication).As<IAuthenticationManager>();
IContainer container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
return container;
var oAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = ApiSettings.AllowInsecureHttp,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(ApiSettings.AccessTokenValidTime),
Provider = container.BeginLifetimeScope().Resolve<IOAuthAuthorizationServerProvider>(),
AccessTokenFormat = new JwtFormatProvider(ApiSettings.ApiAddress),
RefreshTokenProvider = container.BeginLifetimeScope().Resolve<IAuthenticationTokenProvider>()
};