ASP.NET MVC - Legen Sie die benutzerdefinierte IIdentity oder IPrincipal fest

650

Ich muss etwas ziemlich Einfaches tun: In meiner ASP.NET MVC-Anwendung möchte ich eine benutzerdefinierte IIdentity / IPrincipal festlegen. Was auch immer einfacher / geeigneter ist. Ich möchte die Standardeinstellung erweitern, damit ich so etwas wie User.Identity.Idund aufrufen kann User.Identity.Role. Nichts Besonderes, nur ein paar zusätzliche Eigenschaften.

Ich habe Unmengen von Artikeln und Fragen gelesen, aber ich habe das Gefühl, dass ich es schwieriger mache, als es tatsächlich ist. Ich dachte, es wäre einfach. Wenn sich ein Benutzer anmeldet, möchte ich eine benutzerdefinierte IIdentity festlegen. Also dachte ich, ich werde Application_PostAuthenticateRequestin meiner global.asax implementieren. Dies wird jedoch bei jeder Anforderung aufgerufen, und ich möchte nicht bei jeder Anforderung einen Aufruf an die Datenbank senden, bei dem alle Daten aus der Datenbank angefordert und in ein benutzerdefiniertes IPrincipal-Objekt eingefügt werden. Das scheint auch sehr unnötig, langsam und am falschen Ort zu sein (Datenbankaufrufe dort ausführen), aber ich könnte mich irren. Oder woher sonst würden diese Daten kommen?

Daher dachte ich, wenn sich ein Benutzer anmeldet, kann ich meiner Sitzung einige erforderliche Variablen hinzufügen, die ich der benutzerdefinierten IIdentity im Application_PostAuthenticateRequestEreignishandler hinzufüge . Mein Context.Sessionist aber nullda, also ist das auch nicht der richtige Weg.

Ich arbeite jetzt seit einem Tag daran und ich habe das Gefühl, dass mir etwas fehlt. Das sollte nicht zu schwer sein, oder? Ich bin auch ein bisschen verwirrt von all den (halb) verwandten Dingen, die damit einhergehen. MembershipProvider, MembershipUser, RoleProvider, ProfileProvider, IPrincipal, IIdentity, FormsAuthentication.... Bin ich die einzige, findet das alles sehr verwirrend?

Wenn mir jemand eine einfache, elegante und effiziente Lösung nennen könnte, um einige zusätzliche Daten auf einer IIdentity ohne all den zusätzlichen Flaum zu speichern, wäre das großartig! Ich weiß, dass es ähnliche Fragen zu SO gibt, aber wenn die Antwort, die ich brauche, da drin ist, muss ich sie übersehen haben.

Razzie
quelle
1
Hallo Domi, es ist eine Kombination aus dem Speichern von Daten, die sich nie ändern (wie eine Benutzer-ID), oder dem Aktualisieren des Cookies direkt, nachdem der Benutzer Daten geändert hat, die sofort im Cookie wiedergegeben werden müssen. Wenn ein Benutzer dies tut, aktualisiere ich einfach das Cookie mit den neuen Daten. Ich versuche jedoch, keine Daten zu speichern, die sich häufig ändern.
Razzie
26
Diese Frage hat 36.000 Aufrufe und viele positive Stimmen. Ist das wirklich eine so häufige Anforderung - und wenn ja, gibt es keinen besseren Weg als all diese „benutzerdefinierten Dinge“?
Simon_Weaver
2
@Simon_Weaver Es gibt ASP.NET Identity Know, das zusätzliche benutzerdefinierte Informationen im verschlüsselten Cookie einfacher unterstützt.
John
1
Ich stimme Ihnen zu , da zu viele Informationen wie Sie auf dem Laufenden: MemberShip..., Principal, Identity. ASP.NET sollte dies einfacher, einfacher und höchstens zwei Ansätze für den Umgang mit der Authentifizierung machen.
Breitband
1
@Simon_Weaver Dies zeigt deutlich, dass IMHO ein einfacheres, flexibleres Identitätssystem erforderlich ist.
Niico

Antworten:

838

So mache ich es.

Ich habe mich für IPrincipal anstelle von IIdentity entschieden, da ich nicht sowohl IIdentity als auch IPrincipal implementieren muss.

  1. Erstellen Sie die Schnittstelle

    interface ICustomPrincipal : IPrincipal
    {
        int Id { get; set; }
        string FirstName { get; set; }
        string LastName { get; set; }
    }
  2. CustomPrincipal

    public class CustomPrincipal : ICustomPrincipal
    {
        public IIdentity Identity { get; private set; }
        public bool IsInRole(string role) { return false; }
    
        public CustomPrincipal(string email)
        {
            this.Identity = new GenericIdentity(email);
        }
    
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
  3. CustomPrincipalSerializeModel - zum Serialisieren benutzerdefinierter Informationen in Benutzerdatenfelder im FormsAuthenticationTicket-Objekt.

    public class CustomPrincipalSerializeModel
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
  4. Anmeldemethode - Einrichten eines Cookies mit benutzerdefinierten Informationen

    if (Membership.ValidateUser(viewModel.Email, viewModel.Password))
    {
        var user = userRepository.Users.Where(u => u.Email == viewModel.Email).First();
    
        CustomPrincipalSerializeModel serializeModel = new CustomPrincipalSerializeModel();
        serializeModel.Id = user.Id;
        serializeModel.FirstName = user.FirstName;
        serializeModel.LastName = user.LastName;
    
        JavaScriptSerializer serializer = new JavaScriptSerializer();
    
        string userData = serializer.Serialize(serializeModel);
    
        FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
                 1,
                 viewModel.Email,
                 DateTime.Now,
                 DateTime.Now.AddMinutes(15),
                 false,
                 userData);
    
        string encTicket = FormsAuthentication.Encrypt(authTicket);
        HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
        Response.Cookies.Add(faCookie);
    
        return RedirectToAction("Index", "Home");
    }
  5. Global.asax.cs - Das Lesen von Cookies und das Ersetzen des HttpContext.User-Objekts erfolgt durch Überschreiben von PostAuthenticateRequest

    protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
    {
        HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
    
        if (authCookie != null)
        {
            FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
    
            JavaScriptSerializer serializer = new JavaScriptSerializer();
    
            CustomPrincipalSerializeModel serializeModel = serializer.Deserialize<CustomPrincipalSerializeModel>(authTicket.UserData);
    
            CustomPrincipal newUser = new CustomPrincipal(authTicket.Name);
            newUser.Id = serializeModel.Id;
            newUser.FirstName = serializeModel.FirstName;
            newUser.LastName = serializeModel.LastName;
    
            HttpContext.Current.User = newUser;
        }
    }
  6. Zugriff in Rasiermesseransichten

    @((User as CustomPrincipal).Id)
    @((User as CustomPrincipal).FirstName)
    @((User as CustomPrincipal).LastName)

und im Code:

    (User as CustomPrincipal).Id
    (User as CustomPrincipal).FirstName
    (User as CustomPrincipal).LastName

Ich denke, der Code ist selbsterklärend. Wenn nicht, lass es mich wissen.

Um den Zugriff noch einfacher zu gestalten, können Sie außerdem einen Basis-Controller erstellen und das zurückgegebene Benutzerobjekt (HttpContext.User) überschreiben:

public class BaseController : Controller
{
    protected virtual new CustomPrincipal User
    {
        get { return HttpContext.User as CustomPrincipal; }
    }
}

und dann für jeden Controller:

public class AccountController : BaseController
{
    // ...
}

Damit können Sie auf benutzerdefinierte Felder in Code wie folgt zugreifen:

User.Id
User.FirstName
User.LastName

In Innenansichten funktioniert dies jedoch nicht. Dazu müssten Sie eine benutzerdefinierte WebViewPage-Implementierung erstellen:

public abstract class BaseViewPage : WebViewPage
{
    public virtual new CustomPrincipal User
    {
        get { return base.User as CustomPrincipal; }
    }
}

public abstract class BaseViewPage<TModel> : WebViewPage<TModel>
{
    public virtual new CustomPrincipal User
    {
        get { return base.User as CustomPrincipal; }
    }
}

Machen Sie es zu einem Standard-Seitentyp in Views / web.config:

<pages pageBaseType="Your.Namespace.BaseViewPage">
  <namespaces>
    <add namespace="System.Web.Mvc" />
    <add namespace="System.Web.Mvc.Ajax" />
    <add namespace="System.Web.Mvc.Html" />
    <add namespace="System.Web.Routing" />
  </namespaces>
</pages>

und in Ansichten können Sie wie folgt darauf zugreifen:

@User.FirstName
@User.LastName
LukeP
quelle
9
Schöne Umsetzung; Achten Sie darauf, dass RoleManagerModule Ihren benutzerdefinierten Principal durch einen RolePrincipal ersetzt. Das hat mir sehr wehgetan
David Keaveny
9
ok Ich habe die Lösung gefunden, füge einfach einen else-Schalter hinzu, der "" (leere Zeichenfolge) übergibt, da die E-Mail und die Identität anonym sind.
Pierre-Alain Vigeant
3
DateTime.Now.AddMinutes (N) ... wie wird dies gemacht, damit der Benutzer nach N Minuten nicht abgemeldet wird. Kann der angemeldete Benutzer beibehalten werden (wenn der Benutzer beispielsweise "Angemeldet bleiben" aktiviert)?
1110
4
Wenn Sie die WebApiController verwenden, werden Sie setzen müssen Thread.CurrentPrincipalan die Application_PostAuthenticateRequestfür sie arbeiten , wie es lässt sich nicht verlassenHttpContext.Current.User
Jonathan Levison
3
@AbhinavGujjar FormsAuthentication.SignOut();funktioniert gut für mich.
LukeP
109

Ich kann nicht direkt für ASP.NET MVC sprechen, aber für ASP.NET Web Forms besteht der Trick darin, ein zu erstellen FormsAuthenticationTicketund es in ein Cookie zu verschlüsseln, sobald der Benutzer authentifiziert wurde. Auf diese Weise müssen Sie die Datenbank nur einmal aufrufen (oder AD oder was auch immer Sie zur Durchführung Ihrer Authentifizierung verwenden), und jede nachfolgende Anforderung wird anhand des im Cookie gespeicherten Tickets authentifiziert.

Ein guter Artikel dazu: http://www.ondotnet.com/pub/a/dotnet/2004/02/02/effectiveformsauth.html (defekter Link)

Bearbeiten:

Da der obige Link nicht funktioniert, würde ich die Lösung von LukeP in seiner obigen Antwort empfehlen: https://stackoverflow.com/a/10524305 - Ich würde auch vorschlagen, die akzeptierte Antwort in diese zu ändern.

Bearbeiten 2: Eine Alternative für den defekten Link: https://web.archive.org/web/20120422011422/http://ondotnet.com/pub/a/dotnet/2004/02/02/effectiveformsauth.html

John Rasch
quelle
Ich komme aus PHP und habe immer die Informationen wie UserID und andere Elemente, die erforderlich sind, um den eingeschränkten Zugriff zu gewähren, in die Sitzung eingefügt. Das Speichern auf der Client-Seite macht mich nervös. Können Sie kommentieren, warum das kein Problem ist?
John Zumbrum
@JohnZ - Das Ticket selbst wird auf dem Server verschlüsselt, bevor es über das Kabel gesendet wird. Es ist also nicht so, dass der Client Zugriff auf die im Ticket gespeicherten Daten hat. Beachten Sie, dass Sitzungs-IDs auch in einem Cookie gespeichert sind, sodass es nicht wirklich anders ist.
John Rasch
3
Wenn Sie hier sind, sollten Sie sich die Lösung von
LukeP
2
Ich habe mich immer mit dem Potenzial befasst, die maximale Cookie-Größe ( stackoverflow.com/questions/8706924/… ) bei diesem Ansatz zu überschreiten . Ich neige dazu, das Cacheals SessionErsatz zu verwenden, um die Daten auf dem Server zu halten. Kann mir jemand sagen, ob dies ein fehlerhafter Ansatz ist?
Red Taz
2
Netter Ansatz. Ein mögliches Problem dabei ist, dass Ihr Benutzerobjekt mehr als ein paar Eigenschaften hat (und insbesondere wenn verschachtelte Objekte vorhanden sind). Das Erstellen des Cookies schlägt im Hintergrund fehl, sobald der verschlüsselte Wert über 4 KB liegt (viel einfacher zu treffen, als Sie vielleicht denken). Wenn Sie nur Schlüsseldaten speichern, ist das in Ordnung, aber für den Rest müssten Sie immer noch auf DB klicken. Eine weitere Überlegung ist das "Aktualisieren" von Cookie-Daten, wenn das Benutzerobjekt Signatur- oder Logikänderungen aufweist.
Geoffrey Hudik
63

Hier ist ein Beispiel, um die Arbeit zu erledigen. bool isValid wird durch Betrachten eines Datenspeichers festgelegt (sagen wir Ihre Benutzerdatenbank). UserID ist nur eine ID, die ich pflege. Sie können den Benutzerdaten zusätzliche Informationen wie die E-Mail-Adresse hinzufügen.

protected void btnLogin_Click(object sender, EventArgs e)
{         
    //Hard Coded for the moment
    bool isValid=true;
    if (isValid) 
    {
         string userData = String.Empty;
         userData = userData + "UserID=" + userID;
         FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, username, DateTime.Now, DateTime.Now.AddMinutes(30), true, userData);
         string encTicket = FormsAuthentication.Encrypt(ticket);
         HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
         Response.Cookies.Add(faCookie);
         //And send the user where they were heading
         string redirectUrl = FormsAuthentication.GetRedirectUrl(username, false);
         Response.Redirect(redirectUrl);
     }
}

Fügen Sie im Golbal Asax den folgenden Code hinzu, um Ihre Informationen abzurufen

protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
    HttpCookie authCookie = Request.Cookies[
             FormsAuthentication.FormsCookieName];
    if(authCookie != null)
    {
        //Extract the forms authentication cookie
        FormsAuthenticationTicket authTicket = 
               FormsAuthentication.Decrypt(authCookie.Value);
        // Create an Identity object
        //CustomIdentity implements System.Web.Security.IIdentity
        CustomIdentity id = GetUserIdentity(authTicket.Name);
        //CustomPrincipal implements System.Web.Security.IPrincipal
        CustomPrincipal newUser = new CustomPrincipal();
        Context.User = newUser;
    }
}

Wenn Sie die Informationen später verwenden, können Sie wie folgt auf Ihren benutzerdefinierten Principal zugreifen.

(CustomPrincipal)this.User
or 
(CustomPrincipal)this.Context.User

Auf diese Weise können Sie auf benutzerdefinierte Benutzerinformationen zugreifen.

Sriwantha Attanayake
quelle
2
Zu Ihrer Information - es ist Request.Cookies [] (Plural)
Dan Esparza
10
Vergessen Sie nicht, Thread.CurrentPrincipal sowie Context.User auf CustomPrincipal zu setzen.
Russ Cam
6
Woher kommt GetUserIdentity ()?
Ryan
Wie ich im Kommentar erwähnt habe, gibt es eine Implementierung von System.Web.Security.IIdentity. Google über diese Schnittstelle
Sriwantha Attanayake
16

MVC bietet Ihnen die OnAuthorize-Methode, die von Ihren Controller-Klassen abhängt. Sie können auch einen benutzerdefinierten Aktionsfilter verwenden, um die Autorisierung durchzuführen. MVC macht es ziemlich einfach. Ich habe hier einen Blog-Beitrag dazu gepostet. http://www.bradygaster.com/post/custom-authentication-with-mvc-3.0

Brady Gaster
quelle
Die Sitzung kann jedoch verloren gehen und der Benutzer kann sich weiterhin authentifizieren. Nein ?
Dragouf
@brady gaster, ich habe Ihren Blog-Beitrag gelesen (danke!). Warum sollte jemand die in Ihrem Beitrag erwähnte Überschreibung "OnAuthorize ()" über den vom anderen erwähnten Eintrag "... AuthenticateRequest (..)" von global.asax verwenden? Antworten? Wird bei der Einstellung des Hauptbenutzers einer dem anderen vorgezogen?
RayLoveless
10

Hier ist eine Lösung, wenn Sie einige Methoden an @User anschließen müssen, um sie in Ihren Ansichten zu verwenden. Keine Lösung für eine ernsthafte Anpassung der Mitgliedschaft, aber wenn die ursprüngliche Frage nur für Ansichten benötigt würde, würde dies möglicherweise ausreichen. Das Folgende wurde zum Überprüfen einer von einem Autorisierungsfilter zurückgegebenen Variablen verwendet, um zu überprüfen, ob einige Links angezeigt werden sollen oder nicht (nicht für irgendeine Art von Autorisierungslogik oder Zugriffsgewährung).

using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Security.Principal;

    namespace SomeSite.Web.Helpers
    {
        public static class UserHelpers
        {
            public static bool IsEditor(this IPrincipal user)
            {
                return null; //Do some stuff
            }
        }
    }

Fügen Sie dann einfach eine Referenz in die Bereiche web.config ein und rufen Sie sie wie unten in der Ansicht auf.

@User.IsEditor()
Base
quelle
1
In Ihrer Lösung müssen wir jedes Mal erneut Datenbankaufrufe durchführen. Weil das Benutzerobjekt keine benutzerdefinierten Eigenschaften hat. Es hat nur Name und IsAuthanticated
oneNiceFriend
Das hängt ganz von Ihrer Implementierung und dem gewünschten Verhalten ab. Mein Beispiel enthält 0 Zeilen Datenbank- oder Rollenlogik. Wenn man die IsInRole verwendet, könnte sie wiederum in einem Cookie zwischengespeichert werden, glaube ich. Oder Sie implementieren Ihre eigene Caching-Logik.
Basis
3

Basierend auf der Antwort von LukeP , und fügen Sie einige Methoden zum Einrichten timeoutund zur requireSSLZusammenarbeit hinzu Web.config.

Die Referenzen Links

Geänderte Codes von LukeP

1, Set timeoutbasierend auf Web.Config. Die FormsAuthentication.Timeout erhält den Timeout-Wert, der in web.config definiert ist. Ich habe das Folgende als eine Funktion verpackt, die ein ticketZurück zurückgibt.

int version = 1;
DateTime now = DateTime.Now;

// respect to the `timeout` in Web.config.
TimeSpan timeout = FormsAuthentication.Timeout;
DateTime expire = now.Add(timeout);
bool isPersist = false;

FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
     version,          
     name,
     now,
     expire,
     isPersist,
     userData);

2, Konfigurieren Sie das Cookie je nach Konfiguration so, dass es sicher ist oder nicht RequireSSL.

HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
// respect to `RequreSSL` in `Web.Config`
bool bSSL = FormsAuthentication.RequireSSL;
faCookie.Secure = bSSL;
AechoLiu
quelle
3

Also gut, ich bin hier ein ernsthafter Kryptowächter, indem ich diese sehr alte Frage hochziehe, aber es gibt einen viel einfacheren Ansatz, der oben von @Baserz angesprochen wurde. Dies bedeutet, dass eine Kombination aus C # -Erweiterungsmethoden und Caching verwendet wird (Sitzung NICHT verwenden).

Tatsächlich hat Microsoft bereits eine Reihe solcher Erweiterungen im Microsoft.AspNet.Identity.IdentityExtensionsNamespace bereitgestellt . Beispielsweise GetUserId()handelt es sich um eine Erweiterungsmethode, die die Benutzer-ID zurückgibt. Es gibt auch GetUserName()und FindFirstValue(), die Ansprüche basierend auf dem IPrincipal zurückgeben.

Sie müssen also nur den Namespace einschließen und dann aufrufen User.Identity.GetUserName(), um den von ASP.NET Identity konfigurierten Benutzernamen abzurufen.

Ich bin nicht sicher, ob dies zwischengespeichert ist, da die ältere ASP.NET-Identität nicht aus offenen Quellen stammt und ich mich nicht darum gekümmert habe, sie zurückzuentwickeln. Wenn dies nicht der Fall ist, können Sie eine eigene Erweiterungsmethode schreiben, die dieses Ergebnis für einen bestimmten Zeitraum zwischenspeichert.

Erik Funkenbusch
quelle
Warum "Sitzung nicht verwenden"?
Alex
@jitbit - weil die Sitzung unzuverlässig und unsicher ist. Aus dem gleichen Grund sollten Sie die Sitzung niemals aus Sicherheitsgründen verwenden.
Erik Funkenbusch
"Unzuverlässig" kann durch erneutes Auffüllen der Sitzung (falls leer) behoben werden. "Unsicher" - Es gibt Möglichkeiten, sich vor Sitzungsentführungen zu schützen (indem Sie nur HTTPS + andere Methoden verwenden). Aber ich stimme dir tatsächlich zu. Wo würden Sie es dann zwischenspeichern? Infos wie IsUserAdministratoroder UserEmailetc.? Denkst du HttpRuntime.Cache?
Alex
@jitbit - Das ist eine Option oder eine andere Cache-Lösung, wenn Sie sie haben. Stellen Sie sicher, dass der Cache-Eintrag nach einer bestimmten Zeit abläuft. Unsicher gilt auch für das lokale System, da Sie die Cookie- und Ratesitzungs-IDs manuell ändern können. Der Mensch in der Mitte ist nicht das einzige Problem.
Erik Funkenbusch
2

Wenn Sie als Ergänzung zum LukeP-Code für Web Forms-Benutzer (nicht MVC) den Zugriff auf den Code hinter Ihren Seiten vereinfachen möchten, fügen Sie einfach den folgenden Code zu einer Basisseite hinzu und leiten Sie die Basisseite auf allen Ihren Seiten ab:

Public Overridable Shadows ReadOnly Property User() As CustomPrincipal
    Get
        Return DirectCast(MyBase.User, CustomPrincipal)
    End Get
End Property

In Ihrem Code dahinter können Sie also einfach auf Folgendes zugreifen:

User.FirstName or User.LastName

Was mir in einem Web Form-Szenario fehlt, ist, wie man dasselbe Verhalten in Code erhält, der nicht an die Seite gebunden ist, zum Beispiel in http-Modulen, sollte ich in jeder Klasse immer eine Besetzung hinzufügen, oder gibt es eine intelligentere Möglichkeit, dies zu erreichen?

Vielen Dank für Ihre Antworten und danken LukeP da ich Ihre Beispiele als Basis für meine benutzerdefinierten Benutzer verwendet (was jetzt hat User.Roles, User.Tasks, User.HasPath(int), User.Settings.Timeoutund viele andere schöne Dinge)

Manight
quelle
0

Ich habe die von LukeP vorgeschlagene Lösung ausprobiert und festgestellt, dass das Authorize-Attribut nicht unterstützt wird. Also habe ich es ein bisschen modifiziert.

public class UserExBusinessInfo
{
    public int BusinessID { get; set; }
    public string Name { get; set; }
}

public class UserExInfo
{
    public IEnumerable<UserExBusinessInfo> BusinessInfo { get; set; }
    public int? CurrentBusinessID { get; set; }
}

public class PrincipalEx : ClaimsPrincipal
{
    private readonly UserExInfo userExInfo;
    public UserExInfo UserExInfo => userExInfo;

    public PrincipalEx(IPrincipal baseModel, UserExInfo userExInfo)
        : base(baseModel)
    {
        this.userExInfo = userExInfo;
    }
}

public class PrincipalExSerializeModel
{
    public UserExInfo UserExInfo { get; set; }
}

public static class IPrincipalHelpers
{
    public static UserExInfo ExInfo(this IPrincipal @this) => (@this as PrincipalEx)?.UserExInfo;
}


    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Login(LoginModel details, string returnUrl)
    {
        if (ModelState.IsValid)
        {
            AppUser user = await UserManager.FindAsync(details.Name, details.Password);

            if (user == null)
            {
                ModelState.AddModelError("", "Invalid name or password.");
            }
            else
            {
                ClaimsIdentity ident = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
                AuthManager.SignOut();
                AuthManager.SignIn(new AuthenticationProperties { IsPersistent = false }, ident);

                user.LastLoginDate = DateTime.UtcNow;
                await UserManager.UpdateAsync(user);

                PrincipalExSerializeModel serializeModel = new PrincipalExSerializeModel();
                serializeModel.UserExInfo = new UserExInfo()
                {
                    BusinessInfo = await
                        db.Businesses
                        .Where(b => user.Id.Equals(b.AspNetUserID))
                        .Select(b => new UserExBusinessInfo { BusinessID = b.BusinessID, Name = b.Name })
                        .ToListAsync()
                };

                JavaScriptSerializer serializer = new JavaScriptSerializer();

                string userData = serializer.Serialize(serializeModel);

                FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
                         1,
                         details.Name,
                         DateTime.Now,
                         DateTime.Now.AddMinutes(15),
                         false,
                         userData);

                string encTicket = FormsAuthentication.Encrypt(authTicket);
                HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
                Response.Cookies.Add(faCookie);

                return RedirectToLocal(returnUrl);
            }
        }
        return View(details);
    }

Und schließlich in Global.asax.cs

    protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
    {
        HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];

        if (authCookie != null)
        {
            FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
            JavaScriptSerializer serializer = new JavaScriptSerializer();
            PrincipalExSerializeModel serializeModel = serializer.Deserialize<PrincipalExSerializeModel>(authTicket.UserData);
            PrincipalEx newUser = new PrincipalEx(HttpContext.Current.User, serializeModel.UserExInfo);
            HttpContext.Current.User = newUser;
        }
    }

Jetzt kann ich einfach durch Aufrufen auf die Daten in Ansichten und Controllern zugreifen

User.ExInfo()

Um mich abzumelden, rufe ich einfach an

AuthManager.SignOut();

wo AuthManager ist

HttpContext.GetOwinContext().Authentication
Wassili Iwanow
quelle