I have a task to authenticate user with ASP .NET Identity in both ASP .NET Core MVC app and the console app (ask my university teacher why the **** do we need that). When I use it in my "normal" ASP .NET Core MVC app, everything goes OK. But when I'm trying to do it in my console app, it simply throws an error which says "HttpContext must not be null". After I looked inside the SignInManager Microsoft class, I got freaked out. I obviously can't use my DbContext directly because the user passwords stored there are hashed. Can you help me to deal with it?
My Program class code (briefly, ConfigureServices() makes the DI, and my suggestion is that I have to inject something else to make it work):
class Program
{
private static IServiceCollection ConfigureServices()
{
IConfigurationBuilder builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false);
IConfigurationRoot configuration = builder.Build();
string connectionString = configuration["ConnectionString"];
IServiceCollection services = new ServiceCollection();
services.AddLogging();
services.AddDbContext<BreakHealContext>(options => options.UseSqlServer(connectionString, b => b.MigrationsAssembly("IOT")));
services.AddScoped<IExerciseService, ExerciseService>();
services.AddScoped<IInjuryService, InjuryService>();
services.AddScoped<IUserService, UserService>();
services.AddIdentity<User, IdentityRole>(options =>
{
options.Password.RequireDigit = false;
options.Password.RequiredLength = 4;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false;
options.Password.RequireLowercase = false;
})
.AddEntityFrameworkStores<BreakHealContext>()
.AddDefaultTokenProviders();
services.Configure<IdentityOptions>(opts =>
{
opts.User.RequireUniqueEmail = true;
opts.User.AllowedUserNameCharacters =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+/";
});
return services;
}
static async Task Main(string[] args)
{
IServiceCollection services = ConfigureServices();
ServiceProvider serviceProvider = services.BuildServiceProvider();
UserService userService = (UserService)serviceProvider.GetService<IUserService>();
ExerciseService exerciseService = (ExerciseService)serviceProvider.GetService<IExerciseService>();
InjuryService injuryService = (InjuryService)serviceProvider.GetService<IInjuryService>();
UserManager<User> userManager = serviceProvider.GetRequiredService<UserManager<User>>();
SignInManager<User> signInManager = serviceProvider.GetRequiredService<SignInManager<User>>();
IotService iotService = new IotService(userService, exerciseService, injuryService, userManager, signInManager);
await iotService.Run();
Console.WriteLine("Buy buy!)");
}
And the authorization part where I actually use the SignInManager:
private async Task<string> Login()
{
while (true)
{
Console.WriteLine("Enter your email:");
string email = Console.ReadLine();
Console.WriteLine("Enter your password:");
string password = Console.ReadLine();
var user = await this.userManager.FindByNameAsync(email);
if (user != null)
{
if (await this.userManager.IsEmailConfirmedAsync(user) == false)
{
Console.WriteLine("You have not confirmed you email yet");
}
}
else
{
Console.WriteLine("No such email is registered!");
}
#region Check for password
if (user == null) continue;
var result = await this.signInManager.PasswordSignInAsync(email, password, false, false);
if (result.Succeeded)
{
if (user.IsAdmin == true)
{
Console.WriteLine(
"You can't login as an ordinary user because this email is used by an admin!");
}
else
{
return user.Id;
}
}
else
{
Console.WriteLine("Wrong email and/or password");
}
#endregion
}
}
Yep, I've done it by setting the SignInManager.Context property:
signInManager.Context = new DefaultHttpContext {RequestServices = serviceProvider};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With