Storing more information using FormsAuthentication

2019-01-08 05:54发布

问题:

I am using aspx and c# for a setting a authentication cookie for a login.

FormsAuthentication.SetAuthCookie(UserName, True)

I want to store more information in the same cookie. Can I add values to this authentication cookie or do I have to use a second http cookie?

Basically I'm looking for away to store the User's Id so I may be able to access the database using the users table row key

Thanks, Eden

回答1:

You can add user data to the FormsAuthenticationTicket, then generate the cookie yourself.

There's an example in the the MSDN documentation for FormsAuthenticationTicket.

EDIT

Note that when creating the ticket, you need to set the timeout, which in general you will want to be the same as the value configured in web.config. Unfortunately, in the Framework 3.5 or earlier, the FormsAuthentication class does not expose this timeout publicly. For a workaround, use one of the techniques described in the response to this connect feedback item.

UPDATE

That Connect feedback item is no longer there, sadly. Wish you had briefly described what the techniques were.

Yes, it's a pity Microsoft has discarded historical Connect items. IIRC, the two techniques they suggested were:

  1. Use WebConfigurationManager to read the relevant configuration section and get the timeout value.

  2. Create a cookie using FormsAuthentication.GetAuthCookie, decrypt it using FormsAuthentication.Decrypt and inspect the generated FormsAuthenticationTicket.

Or upgrade to .NET 4.x where there is a FormsAuthentication.Timeout property.

See this question for more info



回答2:

You can put whatever you want in the auth cookie as long as it's useful to you. That said, if you're putting sensitive information you should, at the very least, encrypt it, but I'd recommend against putting sensitive information there. You can do something like:

Forms.SetAuthCookie (UserName + "|" + UserId, true);

Then, whenever you need the username or the user id, it is there. Just load the cookie and parse out the values you need.

Again, I'd advise against doing this, especially as I have it presented above. That said, it is possible. You should create accessor methods to pull the data back out:

public int CurrentUserId
{
    get
    {
        int userId = 0;

        if (HttpContext.Current.Request.IsAuthenticated)
        {
            userId = Convert.ToInt32(HttpContext.Current.User.Identity.Name.Split('|')[1]);
        }

        return userId;
    }
}

public string CurrentUserName
{
    get
    {
        string userName = string.Empty;

        if (HttpContext.Current.Request.IsAuthenticated)
        {
            userName = HttpContext.Current.User.Identity.Name.Split('|')[0];
        }

        return userName;
    }
}


回答3:

Yes it is smart to use "|" to put more info. If Microsoft have another overloaded method

public static void SetAuthCookie(String userName, bool createPersistentCookie, string userData)`

Then our life will be much easier, our code will be safer.



回答4:

Pass that user ID as the userName param.

FormsAuthentication.SetAuthCookie(userId, True)

How are you securing your auth tickets?



回答5:

You can store additional information in the UserData property of the FormsAuthenticationTicket:

using Newtonsoft.Json;
using System.Web;
using System.Web.Security;

public class LoggedInUser
{
    public string FirstName { get; set; } = null;
    public bool IsAdmin { get; set; } = false;
}

public static class Authentication
{
    static void SignIn(
        HttpContextBase context,
        string emailAddress,
        bool rememberMe,
        LoggedInUser user = null)
    {
        var cookie = FormsAuthentication.GetAuthCookie(
            emailAddress.ToLower(),
            rememberMe);
        var oldTicket = FormsAuthentication.Decrypt(cookie.Value);
        var newTicket = new FormsAuthenticationTicket(
            oldTicket.Version,
            oldTicket.Name,
            oldTicket.IssueDate,
            oldTicket.Expiration,
            oldTicket.IsPersistent,
            JsonConvert.SerializeObject(user ?? new LoggedInUser()));

        cookie.Value = FormsAuthentication.Encrypt(newTicket);

        context.Response.Cookies.Add(cookie);
    }

    static void SignOut(HttpContextBase context)
    {
        FormsAuthentication.SignOut();
    }

    static LoggedInUser GetLoggedInUser()
    {
        if (HttpContext.Current.User?.Identity?.Name != null && HttpContext.Current.User?.Identity is FormsIdentity identity)
            return JsonConvert.DeserializeObject<LoggedInUser>(identity.Ticket.UserData);

        return new LoggedInUser();
    }
}

Further Reading: https://docs.microsoft.com/en-us/aspnet/web-forms/overview/older-versions-security/introduction/forms-authentication-configuration-and-advanced-topics-cs#step-4-storing-additional-user-data-in-the-ticket