Reputation: 31
I'm working on an application which has two projects:
UI - using ASP.Net MVC. Currently, I am able to get the current logged in user's info(id, name, etc..) inside the UI controller via the User property like this:
using Microsoft.AspNet.Identity;
public class ExamController : Controller
{
IExaminationRepository _repository;
public ExamController()
{
_repository = RepositoryFactory.Get<IExaminationRepository>();
}
[HttpPost]
[Authorize(Roles = "Examiner")]
public ActionResult Create(ExamViewModel viewModel)
{
try
{
ExaminationDomain domain = Mapper.Map<ExamViewModel, ExaminationDomain>(viewModel);
//TODO: Move this to the repository
domain.AuthorId = User.Identity.GetUserId();
_repository.Add(domain);
return RedirectToAction("Index");
}
catch
{
return View();
}
}
}
I would like to move the line: domain.AuthorId = User.Identity.GetUserId();
to my repository concrete implementation like this:
using Microsoft.AspNet.Identity;
using System.Security.Principal;
internal class ExaminationRepository
{
public DBEntities context;
public IPrincipal User;
public ExaminationRepository(DBEntities context)
{
this.context = context;
//I'd like to instantiate User property here:
this.User = "not sure what to instantiate with";
}
public void Add(ExaminationDomain domain)
{
Examination newExam = Mapper.Map<ExaminationDomain, Examination>(domain);
newExam.AuthorId = User.Identity.GetUserId();
newExam.CreatedBy = User.Identity.Name;
newExam.CreatedDate = DateTime.Now;
context.Examinations.Add(newExam);
context.SaveChanges();
}
But I am not sure what to instantiate the User property to in the constructor. I've read some suggestions to use WindowsIdentity.GetCurrent().User
instead of creating a user property but this doesn't contain the user id, only user name.
Any other suggestions on getting user info?
I'd really appreciate some help on this..
Thanks,
Upvotes: 3
Views: 2887
Reputation: 61
You need to instantiate this.User with identity information of current thread:
this.User = System.Threading.Thread.CurrentPrincipal;
var currentIdentity = (System.Security.Claims.ClaimsIdentity)User.Identity;
var userId = currentIdentity.Claims
.Where(p => p.Type.EndsWith("nameidentifier")).Single().Value;
Note that the type of CurrentPrincipal.Identity is an IIdentity. You can cast it to System.Security.Claims.ClaimsIdentity, which contains a property named Claims. This property contains all your claims, including userid and 3rd party token (e.g. Facebook token).
To retrieve UserId, find a claims with Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier"
Upvotes: 0
Reputation: 1952
use HttpContext class witch is a singleton class: first add a using to Microsoft.AspNet.Identity; and then you can do some thing like this:
HttpContext.Current.User.Identity.GetUserId();
since GetUserId is an extension method you have a reference to Microsoft.AspNet.Identity
but if you need to access user information in several places of you app I suggest to have a wrapper class with properties that you need and instantiate when user logs in then store it in session variable this way you have two benefits:
1- you don't need to query db to get username, email etc.. on each user info usage across the app.
2- you don't need assembly that your repository lives to aspnet identity.
Upvotes: 0
Reputation: 2459
I would decouple your repository from the httpcontext with a custom manager. For example I have a interface called IAUthenticationManager
public interface IAUthenticationManager
{
string CurrentUserId();
bool HasCurrentUserRole(string roleName),
}
Easy to test and fully decoupled.
Upvotes: 2
Reputation: 48250
This won't work easily since the repository can be used in many different contexts, even such contexts where user is not set. If you create a concrete dependency in your constructor, your repository will no longer be an independent data provider.
For example, referencing
HttpContext.Current.User.Identity
directly would create a dependency to a web context and the repository would be unusable in non-web contexts.
The best you could do is just to let the repository client provide this:
public void Add(ExaminationDomain domain, IPrincipal principal)
{
Examination newExam = Mapper.Map<ExaminationDomain, Examination>(domain);
newExam.AuthorId = principal.Identity.GetUserId();
newExam.CreatedBy = principal.Identity.Name;
newExam.CreatedDate = DateTime.Now;
context.Examinations.Add(newExam);
context.SaveChanges();
}
or (which could be possible)
public ExaminationRepository(DBEntities context, IPrincipal user)
{
this.context = context;
this.user = user;
}
The latter case could still be correctly resolved by an IoC container if you tell the container how to resolve the dependency.
In a web context, you could set the container to resolve it to HttpContext.Current.User
.
In a non-web context, you could set the container to resolve it to WindowsIdentity.GetCurrent().User
.
Upvotes: 0