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
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!
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?
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
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>();
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.