User Manager for console app without Dependency Injection - c#

I am trying to use the User Manager for a C# console app in .NET 6 without the help of dependency injection. I manage to construct an instance of the User Manager but when I get to using it (create an email with password reset for my users), I get this error:
No IUserTwoFactorTokenProvider named 'Default' is registered.
Here is where I initialize the User Manager in Program.cs:
IConfiguration config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables()
.Build();
IServiceCollection services = new ServiceCollection();
services.AddTransient<UserManager<ApplicationUser>>();
var connectionStrings = config.GetSection("ConnectionStrings");
var messagingConnectionString = connectionStrings.GetValue<string>("Messaging");
AgentConfigDTO appSettingsDTO = new AgentConfigDTO()
{
....
};
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionStrings.ToString(),
sqlServerOptionsAction: sqlOptions =>
{
sqlOptions.EnableRetryOnFailure(
maxRetryCount: 5,
maxRetryDelay: TimeSpan.FromSeconds(30),
errorNumbersToAdd: null);
}
));
// Register UserManager & RoleManager
services.AddIdentity<IdentityUser, IdentityRole>();
services.AddIdentity<ApplicationUser, IdentityRole>(
options =>
{
options.Tokens.ProviderMap.Add("Default", new TokenProviderDescriptor(typeof(IUserTwoFactorTokenProvider<ApplicationUser>)));
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddTransient<IUserStore<IdentityUser>, UserStore<IdentityUser>>();
services.AddTransient<UserManager<IdentityUser>>();
IServiceProvider serviceProvider = services.BuildServiceProvider();
var optionsBuilderApplication = new DbContextOptionsBuilder<ApplicationDbContext>();
var _applicationContext = new ApplicationDbContext(optionsBuilderApplication.UseSqlServer(connectionStrings.ToString()).Options);
IUserStore<ApplicationUser> store = new UserStore<ApplicationUser>(_applicationContext);
UserManager<ApplicationUser> userManager = new UserManager<ApplicationUser>(store, null, new PasswordHasher<ApplicationUser>(), null, null, null, null, serviceProvider, null);
// UserManager & RoleManager require logging and HttpContext dependencies
services.AddLogging();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
new ReportAgent(appSettingsDTO, messagingConnectionString, userManager).RunAsConsole(args);
And this is the method that runs the User Manager:
public void CheckingPasswords()
{
try
{
var date = DateTime.Now.AddMonths(-3);
var userList = _applicationContext.Users.Where(t => t.PasswordExpiry != null && t.PasswordExpiry <= DateTime.Now.AddMonths(-3) && t.Deleted == false && t.PortalAccessEnabled == true).ToList();
if (userList.Count > 0)
{
// Create email
foreach (var user in userList)
{
// Lock user out of the account
user.PortalAccessEnabled = false;
_applicationContext.Update(user);
_applicationContext.SaveChanges();
// Create email
// Exception is thrown on this line of code
var code = _userManager.GeneratePasswordResetTokenAsync(user).ToString();
var url = .
var callbackUrl = url.Replace("[[id]]", user.Id).Replace("[[code]]", code);
Email email = new()
{
...
};
_dbContext.Add(email);
_dbContext.SaveChanges();
}
}
}
}
I am now stuck with this and have no idea how to fix it.
I've also tried manually adding in the Token Provider but that didn't make any difference:
var identityBuilder = new IdentityBuilder(typeof(ApplicationUser), typeof(IdentityRole<string>), services);
identityBuilder.AddTokenProvider("Default", typeof(DataProtectorTokenProvider<ApplicationUser>));
services.AddTransient<UserManager<ApplicationUser>>();

The error message "No IUserTwoFactorTokenProvider named 'Default' is registered" is because you are missing the configuration for the default two-factor token provider. To resolve this, you need to register the default two-factor token provider for UserManager in the services collection.
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddTransient<IUserStore<ApplicationUser>, UserStore<ApplicationUser>>();
services.AddTransient<UserManager<ApplicationUser>>();
services.AddLogging();
services.AddHttpContextAccessor();
}
}
public class ConsoleApp
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly ApplicationDbContext _applicationContext;
public ConsoleApp(UserManager<ApplicationUser> userManager, ApplicationDbContext applicationContext)
{
_userManager = userManager;
_applicationContext = applicationContext;
}
public void CheckingPasswords()
{
try
{
var date = DateTime.Now.AddMonths(-3);
var userList = _applicationContext.Users.Where(t => t.PasswordExpiry != null && t.PasswordExpiry <= DateTime.Now.AddMonths(-3) && t.Deleted == false && t.PortalAccessEnabled == true).ToList();
if (userList.Count > 0)
{
//Create email
foreach (var user in userList)
{
// Lock user out of the account
user.PortalAccessEnabled = false;
_applicationContext.Update(user);
_applicationContext.SaveChanges();
//Create email
var code = _userManager.GeneratePasswordResetTokenAsync(user).Result;
var url = .
var callbackUrl = url.Replace("[[id]]", user.Id).Replace("[[code]]", code);
Email email = new()
{
...
};
_dbContext.Add(email);
_dbContext.SaveChanges();
}
}
}
}
}

Related

Password Reset Token provider in .NET 6 console app - IUserTwoFactorTokenProvider not found

I am attempting to create an email with password reset for my users and I cannot figure out why I receive this error: No IUserTwoFactorTokenProvider named 'Default' is registered.
Here is my Program.cs :
class Program
{
static void Main(string[] args)
{
IConfiguration config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables()
.Build();
IServiceCollection services = new ServiceCollection();
services.AddTransient<UserManager<ApplicationUser>>();
var connectionStrings = config.GetSection("ConnectionStrings");
var messagingConnectionString = connectionStrings.GetValue<string>("Messaging");
AgentConfigDTO appSettingsDTO = new AgentConfigDTO()
{
....
};
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionStrings.ToString(),
sqlServerOptionsAction: sqlOptions =>
{
sqlOptions.EnableRetryOnFailure(
maxRetryCount: 5,
maxRetryDelay: TimeSpan.FromSeconds(30),
errorNumbersToAdd: null);
}
));
// Register UserManager & RoleManager
services.AddIdentity<IdentityUser, IdentityRole>();
services.AddIdentity<ApplicationUser, IdentityRole>(
options =>
{
options.Tokens.ProviderMap.Add("Default", new TokenProviderDescriptor(typeof(IUserTwoFactorTokenProvider<ApplicationUser>)));
}
)
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddTransient<IUserStore<IdentityUser>, UserStore<IdentityUser>>();
services.AddTransient<UserManager<IdentityUser>>();
IServiceProvider serviceProvider = services.BuildServiceProvider();
var optionsBuilderApplication = new DbContextOptionsBuilder<ApplicationDbContext>();
var _applicationContext = new ApplicationDbContext(optionsBuilderApplication.UseSqlServer(connectionStrings.ToString()).Options);
IUserStore<ApplicationUser> store = new UserStore<ApplicationUser>(_applicationContext);
UserManager<ApplicationUser> userManager = new UserManager<ApplicationUser>(store, null, new PasswordHasher<ApplicationUser>(), null, null, null, null, serviceProvider, null);
// UserManager & RoleManager require logging and HttpContext dependencies
services.AddLogging();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
new ReportAgent(appSettingsDTO, messagingConnectionString, userManager).RunAsConsole(args);
}
}
ReportAgent.cs
public void RunAsConsole(string[] args)
{
\\calls RunSystemJob method
}
protected void RunSystemJob(string jobName, string parameters, int commandTimeOutSecs, AgentConfigDTO _appConfig)
{
IReportJob job = null;
switch (jobName.ToLower())
{
case "checkpasswords":
job = new CheckPasswords(_context, parameters, _applicationContext, _userManager, _appConfig);
break;
default:
throw new Exception($"Cannot execute system job {jobName} as it cannot be found.");
}
if (job != null)
{
job.CommandTimeOut = commandTimeOutSecs;
job._appConfig = _appConfig;
job.Run();
}
}
CheckPasswords.cs
public void Run()
{
CheckingPasswords();
}
public void CheckingPasswords()
{
try
{
var date = DateTime.Now.AddMonths(-3);
var userList = _applicationContext.Users.Where(t => t.PasswordExpiry != null && t.PasswordExpiry <= DateTime.Now.AddMonths(-3) && t.Deleted == false && t.PortalAccessEnabled == true).ToList();
if (userList.Count > 0)
{
//Create email
foreach (var user in userList)
{
// Lock user out of the account
user.PortalAccessEnabled = false;
_applicationContext.Update(user);
_applicationContext.SaveChanges();
//Create email
var code = _userManager.GeneratePasswordResetTokenAsync(user).ToString(); // HERE IT THROWS THE EXCEPTION
var url = .
var callbackUrl = url.Replace("[[id]]", user.Id).Replace("[[code]]", code);
Email email = new()
{
ID = 0,
From = _appConfig.DefaultFromEmail,
To = user.Email,
IsHTML = true,
QueuedAt = DateTime.Now,
SendAt = DateTime.Now,
Subject = Core.Resource.Portal.Pages.Common_PortalName + " - " + Core.Resource.Portal.Pages.User_ResetPassword_EmailSubject,
Created = DateTime.Now,
Body = string.Format(Core.Resource.Portal.Pages.User_ResetPassword_EmailBody, callbackUrl),
TrackingID = Guid.NewGuid(),
Status = 1 //Pending
};
_dbContext.Add(email);
_dbContext.SaveChanges();
}
}
}
}
I've also tried manually adding in the Token Provider but that didn't make any difference:
var identityBuilder = new IdentityBuilder(typeof(ApplicationUser), typeof(IdentityRole<string>), services);
identityBuilder.AddTokenProvider("Default", typeof(DataProtectorTokenProvider<ApplicationUser>));
services.AddTransient<UserManager<ApplicationUser>>();
Any help will be greatly appreciated!

Net Core send email background service with Postal and Hangfire

I'm trying to send emails using Hangfire and Postal, but I'm having problems with the HTTPContext. If I execute the shooting through a controller the sending is done without problems, now if I execute a job via Hangfire an expection is generated.
Code startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddHangfire(configuration => configuration
.SetDataCompatibilityLevel(CompatibilityLevel.Version_170)
.UseSimpleAssemblyNameTypeSerializer()
.UseRecommendedSerializerSettings()
.UseSqlServerStorage(Configuration.GetConnectionString("default"), new SqlServerStorageOptions
{
CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
QueuePollInterval = TimeSpan.Zero,
UseRecommendedIsolationLevel = true,
UsePageLocksOnDequeue = true,
DisableGlobalLocks = true
}));
services.Configure<EmailSenderOptions>(Configuration.GetSection("EmailSender"));
services.AddPostal();
services.AddTransient<IEmailSenderEnhance, EmailSender>();
services.AddHttpContextAccessor();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
var options = new DashboardOptions
{
Authorization = new[] { new HangFireAuthorizationFilter() }
};
app.UseHangfireDashboard("/hangfire", options);
app.UseHangfireServer();
RecurringJob.AddOrUpdate<NotificationServices>("SendNotify-", m => m.Notify(1), Cron.Daily);
}
Code NotificationServices.cs
public class NotificationServices
{
private readonly IEmailSenderEnhance _emailSender;
private readonly Config _appConfig;
private readonly IHttpContextAccessor _httpContextAccessor;
public NotificationServices(IEmailSenderEnhance emailSender, IOptions<Config> optionsAccessor, IHttpContextAccessor httpContextAccessor)
{
_emailSender = emailSender;
if (optionsAccessor == null) throw new ArgumentNullException(nameof(optionsAccessor));
_appConfig = optionsAccessor.Value;
_httpContextAccessor = httpContextAccessor;
}
public void Notify(int messageId)
{
var listOSs = Task.Run(async () => await this.SendEmail(messageId));
}
public async Task SendEmail(int orderID)
{
var orderRy = new OrderRepository();
var order = orderRy.Get_By_ID(orderID);
try
{
var requestPath = new Postal.RequestPath
{
PathBase = _httpContextAccessor.HttpContext.Request.PathBase.ToString(),
Host = _httpContextAccessor.HttpContext.Request.Host.ToString(),
IsHttps = _httpContextAccessor.HttpContext.Request.IsHttps,
Scheme = _httpContextAccessor.HttpContext.Request.Scheme,
Method = _httpContextAccessor.HttpContext.Request.Method
};
var emailData = new Postal.Email("SendTest")
{
RequestPath = requestPath,
};
var emailsCopy = $"{order.Salesman.Email},{order.Salesman2.Email},";
emailData.ViewData["to"] = emailsCopy;
emailData.ViewData["Order"] = order;
await _emailSender.SendEmailAsync(emailData);
}
catch (Exception ex)
{
}
}
}
The error is in HttpContext:
_httpContextAccessor.HttpContext.Request.PathBase.ToString()
Is it possible to send e-mails via background with Postal?

Accessing Authenticated User Info in ApplicationDbContext class (ASP.NET Core)

I have an ApplicationDbContext class :
ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, string> where I have override methods on SaveChanges && SaveChangesAsync to include the UpdateAuditEntities method. What i want is to get the user-name / email of the logged in user so every entity that inherits from IAuditableEntity is tagged with the user who created / updated the entity.
private void UpdateAuditEntities()
{
var CurrentUserId = ???;
var modifiedEntries = ChangeTracker.Entries()
.Where(x => x.Entity is IAuditableEntity && (x.State == EntityState.Added || x.State == EntityState.Modified));
foreach (var entry in modifiedEntries)
{
var entity = (IAuditableEntity)entry.Entity;
DateTime now = DateTime.UtcNow;
if (entry.State == EntityState.Added)
{
entity.CreatedDate = now;
entity.CreatedBy = CurrentUserId;
}
else
{
base.Entry(entity).Property(x => x.CreatedBy).IsModified = false;
base.Entry(entity).Property(x => x.CreatedDate).IsModified = false;
}
entity.UpdatedDate = now;
entity.UpdatedBy = CurrentUserId;
}
}
Doing my research, i found a good article here but I have a DesignTimeDbContextFactory implementation like below:
public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
{
public ApplicationDbContext CreateDbContext(string[] args)
{
Mapper.Reset();
IConfigurationRoot configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.AddJsonFile("appsettings.Development.json", optional: true)
.Build();
var builder = new DbContextOptionsBuilder<ApplicationDbContext>();
//IUserResolverService userResolverService = ServiceProviderServiceExtensions.CreateScope()
builder.UseSqlServer(configuration["ConnectionStrings:DefaultConnection"], b => b.MigrationsAssembly("SybrinApp.Pro"));
return new ApplicationDbContext(builder.Options);
}
}
The suggested solution means my ApplicationDbContext will need UserResolverService to instantiate. How can i go about injecting UserResolverService into the DesignTimeDbContextFactory implementation or is there another way to get the currently logged in user in my class ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, string>
OK, have changed my answer. I have borrowed from this url to demonstrate what you can do.
1) first of all create a DependencyResolver class to wrap up the DI
Note that I am assuming that your userResolveService is implementing an IUserResolveService
public class DependencyResolver
{
public IServiceProvider ServiceProvider { get; }
public string CurrentDirectory { get; set; }
public DependencyResolver()
{
// Set up Dependency Injection
IServiceCollection services = new ServiceCollection();
ConfigureServices(services);
ServiceProvider = services.BuildServiceProvider();
}
private void ConfigureServices(IServiceCollection services)
{
// Register any DI you need here
services.AddTransient<IUserResolverService, UserResolverService>();
}
}
2) In your DesignTimeDbContextFactory, replace the commented out line with:
var resolver = new DependencyResolver();
IUserResolverService svc = resolver.ServiceProvider.GetService(typeof(IUserResolverService))
as UserResolverService;
Then go ahead and call as you need

How to create "RoleManager<IdentityRole>" in ASP.Net Core?

I am unable to use RoleManager in my application. I am trying to seed an Admin user in to a .NET Core web application, and I want this user to have a role called "canEdit". What I've got currently produces this error:
System.InvalidOperationException: 'No service for type 'Microsoft.AspNetCore.Identity.RoleManager`1[Microsoft.AspNetCore.Identity.IdentityRole]' has been registered.'
I have tried various ways of doing this. I have tried using Service Provider to do it, dependency injection, etc. but they all give the same error.
ServiceProvider in the Configure method of Startup.cs:
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseAuthentication();
var scopeFactory = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>();
var scope = scopeFactory.CreateScope();
var roleManager = scope.ServiceProvider.GetRequiredService<RoleManager<IdentityRole>>();
DbInitializer dbi = new DbInitializer(roleManager);
dbi.Initialize(context, userManager);
DBInitializer Class:
Constructor:
private readonly RoleManager<IdentityRole> rm;
public DbInitializer(RoleManager<IdentityRole> rm)
{
this.rm = rm;
}
CreateAdmin method:
private async Task CreateAdmin(UserManager<ApplicationUser> userManager, ApplicationDbContext context)
{
IdentityResult ir;
ir = await rm.CreateAsync(new IdentityRole("canEdit"));
IdentityRole canEdit = new IdentityRole("canEdit");
ApplicationUser admin = new ApplicationUser
{
UserName = "Member1#email.com"
};
if (context.Users.Where(u => u.UserName == admin.UserName).Count() == 0)
{
userManager.CreateAsync(admin, "Password123!").Wait();
userManager.AddToRoleAsync(admin, "canEdit").Wait();
}
}
CreateUsers method:
private void CreateUsers(UserManager<ApplicationUser> userManager, ApplicationDbContext context)
{
CreateAdmin(userManager, context).Wait();
ApplicationUser customer1 = new ApplicationUser
{
UserName = "Customer1#email.com"
};
if (context.Users.Where(u => u.UserName == customer1.UserName).Count() > 0)
{
userManager.CreateAsync(customer1, "Password123!").Wait();
}
This repeats for customer2, 3, 4, 5. I can optimise this by removing the need to create an object which I may not need (in the case where the email exists), but I was trying to knock up this method and the CreateAdmin method quickly, then optimise later. Unfortunately I then ran in to an error which I have been unable to fix.
The end goal is for the DbInitializer class to seed 5 regular users, and 1 admin user with extra permissions/claims.
Do you have the Identity services registered?
Also, I ran into issues when I used .Wait() instead of await.
services.AddIdentity<ApplicationUser,IdentityRole>(options=>
{
options.User.RequireUniqueEmail = true;
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false;
})
.AddDefaultTokenProviders()
.AddDefaultUI()
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddAuthorization();
services.AddAuthentication();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
If this helps, here is how I seeded my Db.
public SeedDataBase(IServiceProvider _serviceProvider, ApplicationDbContext _context)
{
serviceProvider = _serviceProvider;
context = _context;
}
private IServiceProvider serviceProvider;
private ApplicationDbContext context;
private ApplicationUser superUser;
public async Task Seed()
{
await CreateSuperUser();
await SeedDb();
}
private async Task CreateSuperUser()
{
var _userManager = serviceProvider.GetRequiredService<UserManager<ApplicationUser>>();
var userExists = await _userManager.GetUsersInRoleAsync("FULLADMIN");
if (userExists.Count() < 1)
{
var _roleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();
var _signinManger = serviceProvider.GetRequiredService<SignInManager<ApplicationUser>>();
superUser = new ApplicationUser()
{
UserName = "superuser#superuser.com",
Email = "superuser#superuser.com",
FirstName = "Super",
LastName = "User",
AccountCreationDate = DateTime.Now.ToShortDateString(),
Access = ApplicationUser.Permissions.FullAdmin
};
var permissions = Enum.GetNames(typeof(ApplicationUser.Permissions));
foreach (var s in permissions)
{
await _roleManager.CreateAsync(new IdentityRole(s));
}
await _userManager.CreateAsync(superUser, "SecureP#ssword1234");
await _userManager.AddToRoleAsync(superUser, Enum.GetName(typeof(ApplicationUser.Permissions), superUser.Access));
}
}
that may help someone in the future ,
you have to use the await for the RoleManager.CreateAsync method
then to verify if the operation was completed successfully
var res = await _roleManager.CreateAsync(new IdentityRole(Role));
if(res.Succeeded)
{
return Ok("created successfully !");
}
If you use IdentityServer4 or Duende.IdentityServer in .NET 5 < with Individual user accounts then edit Startup.cs. Look for the following values:
services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
Edit it to look like this:
services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();

Net Core 2.1 Bearer was not authenticated error in Controller

I am getting an error in net core 2.1:
Bearer was not authenticated.
Failure message: No SecurityTokenValidator available for token: null
The asp net output window is:
info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[7]
Bearer was not authenticated. Failure message: No SecurityTokenValidator available for token: null
info: Microsoft.AspNetCore.Cors.Infrastructure.CorsService[4]
Policy execution successful.
The accounts controller code is here:
namespace quiz_backend.Controllers
{
public class Credentials
{
public string Email { get; set; }
public string Password { get; set; }
}
[Produces("application/json")]
[Route("api/Account")]
public class AccountController : Controller
{
readonly UserManager<IdentityUser> userManager;
readonly SignInManager<IdentityUser> signInManager;
public AccountController(UserManager<IdentityUser> userManager, SignInManager<IdentityUser> signInManager)
{
this.userManager = userManager;
this.signInManager = signInManager;
}
[HttpPost]
public async Task<IActionResult> Register([FromBody] Credentials credentials)
{
var user = new IdentityUser {
UserName = credentials.Email,
Email = credentials.Email
};
var result = await userManager.CreateAsync(user, credentials.Password);
if (!result.Succeeded)
return BadRequest(result.Errors);
await signInManager.SignInAsync(user, isPersistent: false);
// create a token
var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("this is the secret phrase"));
var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);
var jwt = new JwtSecurityToken(signingCredentials: signingCredentials);
return Ok(new JwtSecurityTokenHandler().WriteToken(jwt));
}
}
}
Here is the startup.cs
namespace quiz_backend
{
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.AddCors(options => options.AddPolicy("Cors", builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
}));
services.AddDbContext<QuizContext>(opt =>opt.UseInMemoryDatabase("quiz"));
services.AddDbContext<UserDbContext>(opt => opt.UseInMemoryDatabase("user"));
services.AddIdentity<IdentityUser, IdentityRole>().AddEntityFrameworkStores<UserDbContext>();
var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("this is the secret phrase"));
services.AddAuthentication(options =>{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(cfg => {
cfg.RequireHttpsMetadata = false;
cfg.SaveToken = true;
cfg.TokenValidationParameters = new TokenValidationParameters()
{
IssuerSigningKey = signingKey,
ValidateAudience = false,
ValidateLifetime = false,
ValidateIssuerSigningKey = true
};
});
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseAuthentication();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors("Cors");
app.UseMvc();
}
}
}
This is the front end auth code to attach the token to the header in ts:
export class AuthInterceptor implements HttpInterceptor {
constructor() {}
intercept(req, next) {
var token = localStorage.getItem('token')
var authRequest = req.clone({
headers: req.headers.set('Authorization', `Bearer ${token}`)
})
return next.handle(authRequest)
}
}
Based on your code, it seems that the issue is that the token received is not valid (NULL).
Failure message: No SecurityTokenValidator available for token: null
First of all, you should make sure the token arrives as expected.

Categories