webForumDet fria alternativet

Utöka Context.User.Identity med fler attribut

.NET

3 svar · 593 visningar · startad av lilja

Medlem sedan juli 20041 183 inlägg
Frågan#1

Jag använder idag FormsAuthentication i en MVC site och skulle vilja utöka användarobjektet på ett bra sätt så att jag kan skicka med inställningar såsom namn, användarbild och liknande. Men hur gör jag det? Jag har läst om att ärva från IPrincipal eller GenericPrincipal men får inte riktigt till det.

Kan det vara så att min CustomPrincipal inte sparas mellan anropen? Jag får följande felmeddelande:
Unable to cast object of type 'System.Security.Principal.GenericPrincipal' to type 'MVC3Test.Infrastructure.CustomPrincipal'.

Jag försöker hämta värdet i min vy (aspx/cshtml sidan)

((MVC3Test.Infrastructure.CustomPrincipal)Context.User).Identity.Name

I inloggningen gör jag följande när användarens användarnamn och lösenord stämmer.

FormsAuthentication.SetAuthCookie(userName, createPersistentCookie);

// Extract the forms authentication cookie
string cookieName = FormsAuthentication.FormsCookieName;
HttpCookie authCookie = HttpContext.Current.Request.Cookies[cookieName];
if (null == authCookie)
{
    // There is no authentication cookie.
    return;
} 
FormsAuthenticationTicket authTicket = null;
try
{
    authTicket = FormsAuthentication.Decrypt(authCookie.Value);
}
catch (Exception ex)
{
    // Log exception details (omitted for simplicity)
    return;
}

// Create a new principal
FormsIdentity id = new FormsIdentity(authTicket);
string[] roles = authTicket.UserData.Split('|');
CustomPrincipal principal = new CustomPrincipal(id, roles);
principal.FirstName = "Sven";

// Attach the new principal object to the current HttpContext object
HttpContext.Current.User = principal;

Här försöker jag utöka IPrincipal

public class CustomPrincipal : IPrincipal
{
    private IIdentity _identity;
    private string[] _roles;

    public string FirstName { get; set; }

    public CustomPrincipal(IIdentity identity, string[] roles)
    {
        _identity = identity;
        _roles = new string[roles.Length];
        roles.CopyTo(_roles, 0);
        Array.Sort(_roles);
    }

        
    #region IPrincipal Members

    public IIdentity Identity
    {
        get
        {
            return _identity;
        }
    }

    public bool IsInRole(string role)
    {
        return Array.BinarySearch(_roles, role) >= 0 ? true : false;
    }

    #endregion
}
Medlem sedan juli 2003555 inlägg
#2

Det sparas inte mellan anropen, du måste skapa ditt objekt vid varje anrop. Titta på global.asax, det finns en metod där som du kan överlagra, och då där köra din kod.

Medlem sedan juni 20003 076 inlägg
#3

Men är inte det där lite baklängesprogrammering!? :)

Information om en användare bör väl ligga i en ren användarklass.
Sen kan dock klassen fyllas med hjälp av Context.User.Identity om du vill.

public class User
{
     public int ID {get; set; }
     public string FirstName {get; set; }
     ...
}
User currentUser = AccountService.GetUser(Context.User.Identity);
Medlem sedan juli 20041 183 inlägg
#4

Jag löste det genom att lagra ett JSON objekt i UserData i inloggad användares cookie. Till detta har jag en hjälpklass som serialiserar och desirialiserar den data som finns i UserData.

När jag vill läsa informationen hämtar jag cookien, dekrypterar den och deserialiserar.

Om jag vill ändra informationen hämtar jag cookien, dekrypterar, deserialiserar, skapar en ny ticket och lägger in ny data i UserData samt sparar cookien.

Vid inloggning

var userState = new UserState()
{
    Username = "SomeUsername",
    DisplayName = "SomeDisplayName",
    SomeProperty = "some little text"
};
string userData = userState.ToJson();
var authTicket = new FormsAuthenticationTicket(1, user.Username, DateTime.Now, DateTime.Now.AddMinutes(30), false, userData);

string cookieContents = FormsAuthentication.Encrypt(authTicket);
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, cookieContents)
{
    Expires = authTicket.Expiration,
    Path = FormsAuthentication.FormsCookiePath
};

httpResponse.Cookies.Add(cookie);

Läsa

HttpCookie authCookie = this.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
    FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);

    var userState = UserState.FromJson(authTicket.UserData);
}

Ändra

HttpCookie authCookie = this.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
    FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
    var userState = UserState.FromJson(authTicket.UserData);
    userState.SomeProperty = "some text";
    string newUserData = userState.ToJson();
    var newTicket = new FormsAuthenticationTicket(
        authTicket.Version,
        authTicket.Name,
        authTicket.IssueDate,
        authTicket.Expiration,
        authTicket.IsPersistent,
        newUserData,
        authTicket.CookiePath);
    authCookie.Value = FormsAuthentication.Encrypt(newTicket);
    this.Response.Cookies.Set(authCookie);
}

Hjälpklassen som sparas i UserData

public class UserState
{
    public string Username { get; set; }
    public string DisplayName { get; set; }
    public int SomeProperty { get; set; }

    public string ToJson()
    {
        JavaScriptSerializer serializer = new JavaScriptSerializer();
        return serializer.Serialize(this);
    }

    public static UserState FromJson(string text)
    {
        JavaScriptSerializer serializer = new JavaScriptSerializer();
        return serializer.Deserialize<UserState>(text);
    }
}

Hojta gärna om jag gör något jag inte borde göra :)

264 ms totalt · 4 externa anrop · v20260731065814-full.e96017d9
124 ms — deklarationer (db)
0 ms — hämta statistik (cache)
130 ms — hämta tråd, inlägg och bilagor (db)
132 ms — ändringar (db)