Where/how to populate session with user stored in

2019-06-27 04:32发布

问题:

I've got a session variable that stores my entire user object and when the person logs into my site with forms authentication (using the default MVC provided login) I set the Session variable to the user object like so:

FormsAuthentication.SetAuthCookie(user.Username, model.RememberMe);
SessionUtil.User = user;

All my pages are set to work from this Session object, however the problem arises when they check the remember me box. Close their browser, re-open the browser, and go to my site again. The session is clear at this point, and they didn't log in, but my site still remembers who they are, however all the pages which reference my user object in session break.

I am looking for a way to populate the Session user object with the appropriate data so that in the above scenario the session object would not be empty regardless what page they hit first upon being 'remembered' after visiting my site. Where is a good location to do this? In the application start? In the SessionUtil (right now it's just a static wrapper for session vars)? Base class on the controller? And how do I do that? I've got the logic written to get a user off the username.

Edit: Well application_start doesn't appear to be a good spot because doing this:

        if (User != null)
        {
            SessionUtil.User = EntityServiceFactory.GetService<UserService>().GetUser(User.Identity.Name);
        }

in the method doesn't prevent the problem from happening. I tried doing User.Identity.Name in the if check and then I got a null reference exception, but I am still remembered and logged in when the page actually loads.

Tried the following in Global.asax per Splash-X's comment:

protected void Application_BeginRequest()
    {
        if(User != null)
        {
            SessionUtil.User = EntityServiceFactory.GetService<UserService>().GetUser(User.Identity.Name);
        }
    }

This event is running each request, but User is always null. But what I don't get is the default _LogOnPartial code:

@if(Request.IsAuthenticated) {
<text><strong>@User.Identity.Name</strong> [@Html.ActionLink("Profile", "Profile", "Account")]
[ @Html.ActionLink("Log Off", "LogOff", "Account") ]</text>
}

is still showing me as logged in and the Username is showing fine there.

回答1:

You definitely don't want to use application_start - this only runs once, at the beginning your application spins up. What you could be looking for is session_start, which will run at the first request of a new session:

void Session_Start(object sender, EventArgs e) {
  // set SessionUtil.User here
}

I don't think there's a definitive answer of where this user object of yours must be refreshed. If I had to pick, I would probably do it in your SessionUtil.User getter. Something like this (warning, I did not compile or test this)

public User User
{
    get
    {
        if (Session["user"] != null)
            return Session["user"] as User;

        var user = GetUser(); //however you normally get current user

        Session["user"] = user;

        return user;
    }
}

The net result is that it would become impossible for you to ever request the User property of your session utility to be null.

Edit: just to be clear, session has nothing to do with being "remembered". Your site knows you are logged in and authenticated because you have the ASP.NET authorization cookie. This is independent of Session. Session is simply a memory store scoped and available to each unique user, authenticated or not.