I am making an ASP.Net MVC3 application. I use for now the built in Authentication code that comes with a Visual Studio 2010 project. The problem is dat I need to retrieve the logged in user’s database ID as soon as he has logged in. I do that now by adding code to the Login Action of the Account controller that retrieves the ID from the database by looking it up by username. This works for new logins, but not for “remembered” ones. On restarting the application the last user is automatically logged in again, but the Login code is not fired, so I do not get the database ID.
How can I solve this?
EDIT:
I tried to implement Daniel’s solutions which looks promising and I came up with this code. It nevers gets called though! Where have I gone wrong?
Global.asax.cs:
protected void Application_Start()
{
Database.SetInitializer<StandInContext>(new StandInInitializer());
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
this.AuthenticateRequest +=
new EventHandler(MvcApplication_AuthenticateRequest);
}
void MvcApplication_AuthenticateRequest(object sender, EventArgs e)
{
if(Request.IsAuthenticated)
{
using (var db = new StandInContext())
{
var authenticatedUser = db.AuthenticatedUsers.SingleOrDefault(
user => user.Username == User.Identity.Name);
if (authenticatedUser == null)
return;
var person = db.Persons.Find(authenticatedUser.PersonID);
if (person == null)
return;
Context.User = new CustomPrincipal(
User.Identity, new string[] { "user" })
{
Fullname = person.FullName,
PersonID = person.PersonID,
};
}
}
}
You can use the
AuthenticateRequestevent in your Global.asax.cs:Update:
Now that I see what you’re trying to do a little clearer, I would recommend against using sessions in this particular case. One reason is that Session requires a reference to
System.Web, which you don’t have access to from some places, like a business logic layer in a separate class library.IPrincipal, on the other hand, exists for this very reason.If you need to store more user information than what IPrincioal provides, you simply implement it and add your own properties to it. Easier yet, you can just derive from
GenericPrincipal, which implements IPrincipal and adds some basic role checking functionality:CustomPrincipal.cs
So then you replace the default principal with your own in
AuthenticateRequest, as before:Global.asax.cs
And that is it. The greatest advantage you get is that you automatically get access to your user data from literally everywhere, without having to stick a userId parameter into all your methods. All you need to do is cast the current principal back to CustomPrincipal, and access your data like so:
From your razor views:
From your controllers:
From a business logic layer in another assembly:
To keep things DRY, you could pack this into an extension method and hang it off IPrincipal, like so:
And then you would just do
@User.GetFirstName(),var userName = User.GetFirstName(),Thread.CurrentPrincipal.GetFirstName(), etc.Hope this helps.