'DI issues with custom user manager class
I have issue with DI. I get System.InvalidOperationException: Unable to resolve service for type 'Microsoft.AspNetCore.Identity.UserManager`1[PupilRegister.Models.Entities.Parent]. Case: I need to get logged in user ID. This is why I need to use UserManager. Full source code: https://github.com/Nemes1sX/PupilRegister
AuthController.cs
ing Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using PupilRegister.Configuration;
using PupilRegister.Interfaces;
using PupilRegister.Models.FormRequest;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.Extensions.Options;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using PupilRegister.Models.Entities;
namespace PupilRegister.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class AuthController : ControllerBase
{
private readonly IUserService _userService;
private readonly UserManager<Parent> _userManager;
private readonly JwtConfig _jwtConfig;
public AuthController(IUserService userService, IOptions<JwtConfig> jwtConfig, UserManager<Parent> userManager)
{
_userService = userService;
_userManager = userManager;
_jwtConfig = jwtConfig.Value;
}
[HttpPost]
[Route("login")]
public IActionResult Authenticate([FromBody] LoginRequest request)
{
var parent = _userService.Authenticate(request.Email, request.Password);
if (parent == null)
return BadRequest(new { message = "Username or password is incorrect" });
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.UTF8.GetBytes(_jwtConfig.Secret);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.Name, parent.Id.ToString())
}),
Expires = DateTime.UtcNow.AddDays(7),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
var tokenString = tokenHandler.WriteToken(token);
// return basic user info and authentication token
return Ok(new
{
Token = tokenString,
});
}
[Authorize]
[HttpGet]
[Route("get")]
public async Task<IActionResult> GetUserId()
{
var user = await _userManager.GetUserAsync(HttpContext.User);
return Ok(user.Id);
}
Parent.cs
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace PupilRegister.Models.Entities
{
[Table("Parent")]
public class Parent
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Email { get; set; }
public byte[] PasswordHash { get; set; }
public byte[] PasswordSalt { get; set; }
public virtual List<Pupil> Pupils { get; set; }
}
}
Startup.cs
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.IdentityModel.Tokens;
using PupilRegister.Configuration;
using PupilRegister.DataContext;
using PupilRegister.Infrastructures;
using PupilRegister.Interfaces;
using PupilRegister.Services;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace PupilRegister
{
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.AddScoped<IUserService, UserService>();
services.AddCors();
services.AddControllers();
services.AddControllers().AddNewtonsoftJson(x =>
x.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore);
services.AddScoped<IUserService, UserService>();
//services.AddIdentityCore<Parent>();
services.AddScoped<IPupilService, PupilService>();
services.AddScoped<Mapping>();
var appSettingsSection = Configuration.GetSection("AppSettings");
services.AddDbContextPool<PupilRegisterContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("PupilRegisterDatabase")));
services.Configure<JwtConfig>(appSettingsSection);
// configure jwt authentication
var appSettings = appSettingsSection.Get<JwtConfig>();
var key = Encoding.ASCII.GetBytes(appSettings.Secret);
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(x =>
{
x.Events = new JwtBearerEvents
{
OnTokenValidated = context =>
{
var userService = context.HttpContext.RequestServices.GetRequiredService<IUserService>();
var userId = int.Parse(context.Principal.Identity.Name);
var user = userService.GetById(userId);
if (user == null)
{
// return unauthorized if user no longer exists
context.Fail("Unauthorized");
}
return Task.CompletedTask;
}
};
x.RequireHttpsMetadata = false;
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false
};
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
