I created a selfhosting webapp (Microsoft.AspNetCore.Owin) as recommended in stackoverflow by #Anouar.
It works as expected. But I can't get user information from the context. There doesn't seem to be any Claim in HttpContext.Users.Claims (nrOfClaims = 0).
public class SayHi : ControllerBase
{
[Route("sayhi/{name}")]
public IActionResult Get(string name)
{
var userId = HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value;
var nrOfClaims = HttpContext.User.Claims.Count();
Is it possible to get the username and the user-domainname via HttpContext here?
I searched various sites. I tried IHttpContextAccessor stackoverflow via constructor dependency injection. But the HttpContextAccessor seems to be the same as HttpContext itself.
Related
I am trying to refactor my api into a minimal api. Previously I've been using ControllerBase.HttpContext to get the user like this:
var emial = HttpContext.User.FindFirstValue(ClaimTypes.Email);
The method that I want to use for my endpoint mapping should be something like this:
public static void MapSurveyEndpoints(this WebApplication app) {
app.MapPost("/api/Surveys", AddSurveysAsync);
}
public static async Task<Survey> AddSurveysAsync(ISurveyRepository repo, Survey survey) {
var email = ...; //get current user email
survey.UserEmail = email;
return await repo.AddSurveysAsync(survey);
}
What would be another approach for getting the user without using controller?
You can take the HttpContext as a parameter of your endpoint. ASP.NET Core will then provide that to you.
public static async Task<Survey> AddSurveysAsync(
HttpContext context,
ISurveyRepository repo,
Survey survey)
Minimal APIs have several parameter binding sources for handlers, including special types, like HttpContext as suggested in another answer, but if you need only the user info you can add just ClaimsPrincipal (which is one of the special types) parameter to your method:
app.MapGet("/...", (..., ClaimsPrincipal user) => user.Identity.Name);
I've an app that will have multiples level of organization, and for each level, there will be rights(admin-reader-...).
I want to create(and maintain) a list of roles for each user, but it means that a lot of those roles name will be dynamic, like {id-of-the-organization]-admin.
Therefore, I cannot just do the usual Authorize:
[Authorize(Roles = "Administrator, PowerUser")]
public class ControlAllPanelController : Controller
{
public IActionResult SetTime() =>
Content("Administrator || PowerUser");
[Authorize(Roles = "Administrator")]
public IActionResult ShutDown() =>
Content("Administrator only");
}
I would like to have something like
public class ControlAllPanelController : Controller
{
[Authorize]
public IActionResult SetTime(Guid organizationId) {
someService.Authorize(organizationId+"-SetTime");//Throw exception or return boolean
//... rest of my logic
}
}
Not sure how to achieve this? I've seen example of this with the IAuthorize service, but this was requiring to provide policies name, which I don't have for this case(Or maybe there is one by default but I don't know its name. `
I've seen that the ClaimsPrincipal has a IsInRole, but I'm not totally sure it get the latest information from Asp.Net Core Identity Framwork(from the user manager) (only what is stored inside the token?)?
You can use HttpContext to look at the claims in the JWT.
I have recently been working with authorizations in .NET API and this is what I done:
var identity = this.HttpContext.User.Identities.FirstOrDefault();
var role = identity.Claims.FirstOrDefault(x => x.Type == "role").Value;
if (role != "Admin")
{
return Unauthorized("You don't have to correct permissons to do this.");
}
So I'm getting the Identity details, then searching the claims for the role claim.
As a side note, Im using this in a controller inheriting from ControllerBase so I believe HttpContext is a property of this class so no need to inject it if you're using this. Else, you'd probably have to use it via DI, but should all work the same.
I have a controller decorated with [Authorize] attribute. I would like to accomplish the following so that I don't have to repeatedly create repository obj and pass currentUser in each method:
[Authorize]
public class HomeController : ApiController
{
Repository repo;
public HomeController()
{
var userName = User.Identity.IsAuthenticated ? User.Identity.Name : null;
repo = new Repository(userName);
}
}
I know User.Identity is not available in constructor or in Initialize method.
What is the best practice to inject authenticated user in controller constructor.
If we use dependency injection - while registering our custom created UserResolverService inside WebApiConfig.cs in Register method - User.Identity is not available at this point as well.
This is a very common issue with web api but somehow couldn't find any article showing proper solution.
Is it really achievable and if yes - can you please provide some sample code?
Here is how I worked around this (not sure how appropriate this method is, but it works).
In your BaseContoller (a controller from which all other controllers inherit from) create instance of Repository like so:
private Repository _Repository;
private Repository Repository
{
get
{
_Repository.InjectUsername(User.Identity.Name); // value is already available here
return _Repository;
}
set
{
_Repository = new Repository();
}
}
Notice how your Repository has InjectUsername method. That method will simple assign passed parameter to some Repository's property, like so:
public class Repository
{
private string Username { get; set; }
public void InjectUsername(string username)
{
Username = username;
}
}
Every time you will call some method in repository from a controller action you will inject usrename which will already exist, and you won't have to duplicate code by passing username to every method in repository every time you call it.
You can register a factory delegate and get user identity from HttpContext.Current.
Here's a sample code for simpleinjector
container.Register<IPrincipal>(() => HttpContext.Current.User);
I have two databases.
application_db
registry_db
application_db is used for the application to get work and uses the ApplicationDbContext.
registry_db is used to manage all accounts. I would like to create first an account over my registry service and then insert the created account (with less information) into application db. Registry_db is using RegistryDbContext.
I've injected both contexts successfully (ApplicationDbContext & RegistryDbContext) inside my registry service over the dependency injection.
My Startup looks like this:
services.AddCors();
services
.AddDbContext<RegistryDbContext>(
options => options
.UseNpgsql(
Configuration.GetConnectionString("DefaultConnection"),
b => b.MigrationsAssembly("Codeflow.Registry")
)
);
services
.AddDbContext<ApplicationDbContext>(
options => options
.UseNpgsql(
Configuration.GetConnectionString("ProductionConnection"),
b => b.MigrationsAssembly("Codeflow.Registry")
)
);
Inside my registry service, I can get the userManager over the dependencies injection and create an account. On default the userManager uses the RegistryDbContext. Once an account is created successfully over the registry service, I would like to create the same account in the application_db (over the ApplicationDbContext). But I get stuck in this line of code
// first I am creating the account in registry_db
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
// once the account is created, I would like to create the account on application_db
// here I am getting the dbContext for the application_db
// I can get it also over the dependency injection if needed
using (ApplicationDbContext dbCtx = new ApplicationDbContext())
{
// Here I am getting the Error. The context is ok, but an error appeard with ApplicationUser.
var test = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(dbCtx));
}
}
I get this error message:
Error: There is no argument given that corresponds to the required
format parameter
'optionsAccessor' of 'UserManager. UserManager(IUserStore, IOptions,
IPasswordHasher,
IEnumerable>,
IEnumerable>, ILookupNormalizer,
IdentityErrorDescriber, IServiceProbider,
ILogger>)'
My ApplicationUser class looks like this:
public class ApplicationUser : IdentityUser<Guid>
{
public Guid GenderId { get; set; }
[ForeignKey("GenderId")]
public Gender Gender { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime BirthDay { get; set; }
}
What is wrong or missing?
I tried already to follow this post here but no luck. Is there an other way to create an userManager instance with an other context?
using (var db = new TenantDBContext("connectionString"))
{
db.Database.Migrate();
var store = new UserStore<IdentityUser>(db);
var user = new IdentityUser("test");
var result = await store.CreateAsync(user);
}
It is dependency injection over constructor. With DI, you shouldn't initialize your service directly. You should register your Service and ApplicationContext in Startup.cs.
When you need your Service, you should inject it over constructor into a controller, and DI chain will automatically inject instance of ApplicationContext into the Service.
Of course, if you don't need your service for each method in a controller, you can initialize it into method :
[Route("api/[controller]")]
public class MyController : Controller
{
[HttpGet]
public async IEnumerable<object> Get([FromServices] ApplicationContext context,
MyType myMainParam)
{
...
}
}
However what you really need to do is to implement your own version of UserManagerFactory which this link might be of help.
this post might help too.
P.S :
Take a look at #Singularity222 answer in this thread. he has done the same thing you wanna do, in his repo.
Also we have this thread where the owner of Identity project (!) said you need to implement your own version of UserStore.
I think you are referencing the wrong assembly.
The UserManager class which its constructor receive only one argument UserStore is not ASP.Net Core UserManager, it is ASP.Net UserManager. Please check the following details,
ASP.Net UserManager (Microsoft.AspNet.Identity.Core.dll):
https://msdn.microsoft.com/en-us/library/dn468199(v=vs.108).aspx
ASP.Net Core UserManager (Microsoft.AspNetCore.Identity.dll, Microsoft.Extensions.Identity.Core.dll):
https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.usermanager-1?view=aspnetcore-2.0
So my suggestion is, fix your identity library reference to use .Net Core one.
im using vs 2013, mvc5 and ef6 + unity.mvc5:
my account controller class has this constructor:
public AccountController(UserManager<ApplicationUser> userManager)
{
this.UserManager = userManager;
}
and this is my unity config:
container.RegisterType(typeof(AccountController),
new InjectionConstructor(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>())));
when i try to register a new user i get this exception:
Cannot access a disposed object.
Object name: 'UserManager`1'.
on this line of code and register action:
var result = await UserManager.CreateAsync(user, model.Password);
when i remove unity and set dependecy resolver to default it works just fine.
i`v tried many unity configs but didnt work...
thanks alot for reading.
i found the solution, changed the unity config to this:
container.RegisterType<IUserStore<ApplicationUser>,
UserStore<ApplicationUser>>(new InjectionConstructor(new ApplicationDbContext()));
thanks all.
Do NOT create a parameterless constructor, (I can't vote it down as I don't have enough reputation), that answer totally avoids IoC and instead tries to build up the object by knowing the entire dependency hierarchy for the object, i.e. AccountController needs to know that it has a dependency on UserStore and it needs to know that Userstore has a dependency on UserContext. This is exactly what DI containers are there to avoid!
It is hard to provide you with an exact answer as there is a lot of your code missing.
One thing that looks odd to me is that you have an uppercase UserManger, that usually means that you are using it as a type, not referencing a local private variable. Can you show me the rest of the code?
Also, I would question why you are not referencing everything via Interfaces. That is by far the preferred way to set up proper DI.
I will try to knock up some test code that shows what I would do and then post this here, if you could answer those questions in the meantime that would be great.
Cheers Mike
Here is what I would do.
In your controller
public class HomeController : Controller
{
private IUserManager<ApplicationUser> userManager;
public HomeController(IUserManager<ApplicationUser> userManager)
{
this.userManager = userManager;
}
public ActionResult Index()
{
var user = "user";
var password = "password";
var result = userManager.CreateAsync(user, password);
return View();
}
}
Interface for UserManager
public interface IUserManager<T> where T : ApplicationUser
{
int CreateAsync(string user, string password);
}
Actual UserManager class
public class UserManager<T> : IUserManager<T> where T : ApplicationUser
{
private IUserStore<ApplicationUser> userStore;
public UserManager(IUserStore<ApplicationUser> userStore)
{
this.userStore = userStore;
}
public int CreateAsync(string user, string password)
{
return 0;
}
}
Interface for UserStore
public interface IUserStore<T> where T : ApplicationUser
{
}
Actual UserStore
public class UserStore<T> : IUserStore<T> where T : ApplicationUser
{
}
Unity configuration
container.RegisterType(typeof (IUserManager<>), typeof (UserManager<>));
container.RegisterType(typeof (IUserStore<>), typeof (UserStore<>));
Hope this helps.
There is obviously lots that is not the same as your app, i.e. not doing the method call async, not reading the password in from the model, etc. but it should give an idea of how to solve the problem that you outlined.
This solution will give you proper constructor dependency injection, which will allow you to have all of your configuration in one place (i.e. the container config) and it will give you interfaces in your constructors which will make it much easier for you to mock those dependencies in your unit tests.
Cheers Mike