如何解决如何将包含UserManager <ApplicationUser>的services.AddSingleton添加到启动类
添加服务时出现错误。启动类中的AddSingleton。
它一直起作用,直到我尝试添加UserManager位。我不知道用Usermanager实例化类的语法。
我正在关注this code,但是我需要使用.netCore身份来管理用户,而他正在使用简单的字典。
我得到的错误是:
InvalidOperationException:无法解析作用域服务 'Microsoft.AspNetCore.Identity.UserManager`1 [ibasis_api.Areas.Identity.Data.ibasis_apiUser]' 来自根提供商。
我怀疑错误的行是:
services.AddSingleton<IJWTAuthenticationManager>(x =>
new JWTAuthenticationManager(tokenKey,x.GetService<IRefreshTokenGenerator>(),x.GetService<UserManager<ibasis_apiUser>>()
));
启动:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ibasisLiveDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")
));
services.AddDbContext<IdentityContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("ibasis_apiAuthContextConnection")
));
var appSettingsSection = Configuration.GetSection("AppSettings");
services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
var appSettings = appSettingsSection.Get<AppSettings>();
var tokenKey = appSettings.Secret;
var key = Encoding.ASCII.GetBytes(appSettings.Secret);
var builder = services.AddIdentityCore<ibasis_apiUser>(o =>
{
// configure identity options
o.Password.RequireDigit = false;
o.Password.RequireLowercase = false;
o.Password.RequireUppercase = false;
o.Password.RequireNonAlphanumeric = false;
o.Password.RequiredLength = 6;
o.Lockout.MaxFailedAccessAttempts = 10;
o.User.RequireUniqueEmail = false;
o.SignIn.RequireConfirmedEmail = false;
}).AddRoles<IdentityRole>();
services.AddIdentity<ibasis_apiUser,IdentityRole>()
.AddEntityFrameworkStores<IdentityContext>()
.AddDefaultTokenProviders();
IdentityModelEventSource.ShowPII = true;
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(x =>
{
x.RequireHttpsMetadata = false;
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,IssuerSigningKey = new SymmetricSecurityKey(key),ValidateIssuer = false,ValidateAudience = false,ValidateLifetime = true,ClockSkew = TimeSpan.Zero,};
});
services.AddControllers();
services.AddSwaggerGen(setup =>
{
setup.SwaggerDoc(
"V1",new OpenApiInfo
{
Title = "iBais API",Version = "v1"
}
);
});
//var userManager = (UserManager<ibasis_apiUser>)Scope.ServiceProvider.GetService(typeof(UserManager<ibasis_apiUser>));
//UserManager<ibasis_apiUser> userManager =serviceProvider.GetRequiredService<UserManager<ibasis_apiUser>>();
//UserManager<ibasis_apiUser> userManager = new UserManager<ibasis_apiUser>(); services.G serviceProvider.GetRequiredService<UserManager<ibasis_apiUser>>();
services.AddSingleton<ITokenRefresher>(x =>
new TokenRefresher(key,x.GetService<IJWTAuthenticationManager>(),x.GetService<UserManager<ibasis_apiUser>>() //Suspect Line
));
services.AddSingleton<IRefreshTokenGenerator,RefreshTokenGenerator>();
services.AddSingleton<IJWTAuthenticationManager>(x =>
new JWTAuthenticationManager(tokenKey,x.GetService<UserManager<ibasis_apiUser>>()//Suspect Line
));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app,IWebHostEnvironment env,ILoggerFactory loggerFactory)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSwagger();
app.UseSwaggerUI(x =>
{
x.SwaggerEndpoint("/swagger/v1/swagger.json","iBasis API v1");
//x.RoutePrefix = string.Empty;
});
loggerFactory.AddFile(Configuration.GetSection("Logging"));
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
JWTAuthenticationManager界面
public interface IJWTAuthenticationManager
{
Task<AuthenticationResponse> Authenticate(string username,string password);
Task<AuthenticationResponse> Authenticate(string username,Claim[] claims);
}
JWTAuthenticationManager
public class JWTAuthenticationManager : IJWTAuthenticationManager
{
private readonly string tokenKey;
private readonly IRefreshTokenGenerator refreshTokenGenerator;
private readonly UserManager<ibasis_apiUser> _userManager;
public JWTAuthenticationManager(string tokenKey,IRefreshTokenGenerator refreshTokenGenerator,UserManager<ibasis_apiUser> usermanager)
{
this.tokenKey = tokenKey;
this.refreshTokenGenerator = refreshTokenGenerator;
_userManager = usermanager;
}
public async Task<AuthenticationResponse> Authenticate(string username,Claim[] claims)
{
var token = GenerateTokenString(username,DateTime.UtcNow,claims);
var refreshToken = refreshTokenGenerator.GenerateToken();
var user = await _userManager.FindByNameAsync(username);
user.RefreshTokens = refreshToken;
await _userManager.UpdateAsync(user);
return new AuthenticationResponse
{
JwtToken = token,RefreshToken = refreshToken
};
}
public async Task<AuthenticationResponse> Authenticate(string username,string password)
{
var user = await _userManager.FindByNameAsync(username);
if(user != null && !await _userManager.CheckPasswordAsync(user,password))
{
return null;
}
var token = GenerateTokenString(username,DateTime.UtcNow);
var refreshToken = refreshTokenGenerator.GenerateToken();
//Save Token
user.RefreshTokens = refreshToken;
await _userManager.UpdateAsync(user);
return new AuthenticationResponse
{
JwtToken = token,RefreshToken = refreshToken
};
}
string GenerateTokenString(string username,DateTime expires,Claim[] claims = null)
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(tokenKey);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(
claims ?? new Claim[]
{
new Claim(ClaimTypes.Name,username)
}),//NotBefore = expires,Expires = expires.AddMinutes(2),SigningCredentials = new SigningCredentials(
new SymmetricSecurityKey(key),SecurityAlgorithms.HmacSha256Signature)
};
return tokenHandler.WriteToken(tokenHandler.CreateToken(tokenDescriptor));
}
private async Task<bool> IsValidUsernameAndPassowrd(string username,string password)
{
var user = await _userManager.FindByNameAsync(username);
return await _userManager.CheckPasswordAsync(user,password);
}
}
TokenRefresher
public class TokenRefresher : ITokenRefresher
{
private readonly byte[] key;
private readonly IJWTAuthenticationManager jWTAuthenticationManager;
private readonly UserManager<ibasis_apiUser> _userManager;
public TokenRefresher(byte[] key,IJWTAuthenticationManager jWTAuthenticationManager,UserManager<ibasis_apiUser> usermanager)
{
this.key = key;
this.jWTAuthenticationManager = jWTAuthenticationManager;
_userManager = usermanager;
}
public async Task<AuthenticationResponse> Refresh(RefreshCred refreshCred)
{
var tokenHandler = new JwtSecurityTokenHandler();
SecurityToken validatedToken;
var pricipal = tokenHandler.ValidateToken(refreshCred.JwtToken,new TokenValidationParameters
{
ValidateIssuerSigningKey = true,ValidateLifetime = false //here we are saying that we don't care about the token's expiration date
},out validatedToken);
var jwtToken = validatedToken as JwtSecurityToken;
if (jwtToken == null || !jwtToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256,StringComparison.InvariantCultureIgnoreCase))
{
throw new SecurityTokenException("Invalid token passed!");
}
var userName = pricipal.Identity.Name;
var user = await _userManager.FindByNameAsync(userName);
if (refreshCred.RefreshToken != user.RefreshTokens)
{
throw new SecurityTokenException("Invalid token passed!");
}
return await jWTAuthenticationManager.Authenticate(userName,pricipal.Claims.ToArray());
}
}
解决方法
因此,我用一些代码示例扩展了我的评论
首先,考虑将IJWTAuthenticationManager
注册为范围服务:
services.AddScoped<IJWTAuthenticationManager>(serviceProvider =>
ActivatorUtilities.CreateInstance<JWTAuthenticationManager>(serviceProvider,tokenKey));
您可以使用ActivatorUtilities
类将tokenKey
作为自定义参数传递,同时由DI容器填充其他参数。
如果IJWTAuthenticationManager
必须是单身,请尝试注入IHttpContextAccessor
:
services.AddHttpContextAccessor();
services.AddSingleton<IJWTAuthenticationManager>(serviceProvider =>
ActivatorUtilities.CreateInstance<JWTAuthenticationManager>(serviceProvider,tokenKey));
然后您的JWTAuthenticationManager
类应如下所示:
public class JWTAuthenticationManager : IJWTAuthenticationManager
{
private readonly string tokenKey;
private readonly IRefreshTokenGenerator refreshTokenGenerator;
private readonly IHttpContextAccessor _httpContextAccessor;
public JWTAuthenticationManager(
string tokenKey,IRefreshTokenGenerator refreshTokenGenerator,IHttpContextAccessor httpContextAccessor)
{
this.tokenKey = tokenKey;
this.refreshTokenGenerator = refreshTokenGenerator;
_httpContextAccessor = httpContextAccessor;
}
public async Task<AuthenticationResponse> Authenticate(string username,Claim[] claims)
{
// Resolve UserManager for current request
var serviceProvider = _httpContextAccessor.HttpContext.RequestServices;
var userManager = serviceProvider.GetRequiredService<UserManager<ibasis_apiUser>>();
// The rest of your method
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。