开发者

How to tap into the automatic repeated login?

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 retri开发者_JAVA技巧eve 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 AuthenticateRequest event in your Global.asax.cs:

protected void Application_AuthenticateRequest()
{
    if (Request.IsAuthenticated)
    {
        // retrieve user from repository
        var user = _membershipService.GetUserByName(User.Identity.Name);
        // do other stuff
    }
}

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

public class CustomPrincipal : GenericPrincipal
{
    public CustomPrincipal(IIdentity identity, string[] roles)
        : base(identity, roles) { }

    public Guid Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email  { get; set; }
    ...
}

So then you replace the default principal with your own in AuthenticateRequest, as before:

Global.asax.cs

protected void Application_AuthenticateRequest()
{
    if (Request.IsAuthenticated)
        Context.User = _securityService.GetCustomPrincipal(User.Identity.Name);
}

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:

<p>Hello, @((CustomPrincipal)User).FirstName!</p>

From your controllers:

var firstName = ((CustomPrincipal)User).FirstName;

From a business logic layer in another assembly:

var firstName = ((CustomPrincipal)Thread.CurrentPrincipal).FirstName;

To keep things DRY, you could pack this into an extension method and hang it off IPrincipal, like so:

public static class PrincipalExtensions
{
    public static string GetFirstName(this IPrincipal principal)
    {
        var customPrincipal = principal as CustomPrincipal;
        return customPrincipal != null ? customPrincipal.FirstName : "";
    }
}

And then you would just do @User.GetFirstName(), var userName = User.GetFirstName(), Thread.CurrentPrincipal.GetFirstName(), etc.

Hope this helps.


I wasn´t thinking clear. I was trying to store the userinfo in the Session object, while it available through the User object. Sorry to have wasted your time.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜