2009-04-22 4 views
4

Grundsätzlich logge ich mich mit OpenId in meine Website ein, sehr ähnlich wie ich es bei SO sehe. Wenn ich die Informationen zurückbekomme, werfe ich sie in eine Datenbank und erstelle meinen "Registrierten Benutzer". Ich setze meinen AuthCookie:Wie kann eine Site wie Stack Overflow Benutzerinformationen in ASP.NET MVC weitergeben?

Dann kann ich das für den Benutzernamen verwenden. Ich möchte jedoch lieber das gesamte Objekt übergeben als nur die Zeichenfolge für den Anzeigenamen. Also meine Frage ist:

Wie macht es SO?

Erweitern/überschreiben sie die SetAuthCookie(string, bool)-Methode, um das Benutzerobjekt zu akzeptieren, d. H. SetAuthCookie(User(object), bool).

Was ist die beste Möglichkeit, ein Benutzerobjekt so zu persistieren, dass es für mein Benutzersteuerelement auf jeder einzelnen Seite meiner Webanwendung verfügbar ist?

Vielen Dank im Voraus!

+0

Was sind Sie mit OpenID anmelden verwenden? Ich habe http://code.google.com/p/dotnetopenid/ in der Vergangenheit mit einigem Erfolg verwendet - ich bin sicher, dass es Beispiele bietet, die zeigen, was Sie hier tun möchten. – Noldorin

+0

Ich benutze ihre ASP.NET MVC-Beispiel, um sich anzumelden. Nur den Kern, dann in ihrer Methode in der case-Anweisung (tis, wo ich gor die Zeile über. Ursprünglich sah dieser Code so aus ... FormsAuthentication.SetAuthCookie (response.ClaimedIdentifier, false); Ich habe die Zeichenfolge einfach durch den Anzeigenamen meines Benutzers ersetzt.Ich möchte einige grundlegende Informationen mit ihr pushen, wie hier, wo sie Ihnen Ihre Punktzahl, Ihre userId, mitteilen (befindet sich im Hyperlink) usw. –

+1

Jeff! NUTZEN SIE DISPLAYNAME NICHT FÜR IHREN NUTZERNAME! Entschuldigung, aber dies ist eine riesige Sicherheitslücke. Sie müssen den ClaimedIdentifier für den ersten Parameter zu SetAuthCookie verwenden. Ja, das bedeutet Kontrollen wie LoginName werden die Ergebnisse nicht erzeugen Sie wollen, aber ein kleines bisschen Bequemlichkeit auf Ihrer Seite ist es nicht wert, so viel Sicherheit zu opfern. –

Antwort

3

Sie können dieses Verhalten erreichen, indem Sie implementing Ihre benutzerdefinierte Membership Provider oder ein vorhandenes erweitern. Der Provider speichert Benutzerinformationen basierend auf einem Schlüssel (oder nur nach Benutzernamen) und bietet Zugriff auf die Klasse MembershipUser, die Sie beliebig erweitern können. Wenn Sie also FormsAuthentication.SetAuthCookie(...) anrufen, legen Sie grundsätzlich den Benutzerschlüssel fest, auf den der Provider zugreifen kann.

Wenn Sie Membership.GetUser() aufrufen, ruft die Mitgliedschaftsinfrastruktur den zugrunde liegenden Provider auf und ruft die Methode GetUser(...) auf, die den Schlüssel des aktuellen Benutzers bereitstellt. Damit erhalten Sie das aktuelle Benutzerobjekt.

1

Eine Möglichkeit besteht darin, in Ihre Steuerung eine Klasse einzuschleusen, die für das Abrufen von Informationen für den aktuell angemeldeten Benutzer zuständig ist. Hier ist, wie ich es gemacht habe. Ich habe eine Klasse namens WebUserSession erstellt, die eine Schnittstelle namens IUserSession implementiert. Dann verwende ich die Abhängigkeitsinjektion, um es in den Controller zu injizieren, wenn die Controller-Instanz erstellt wird. Ich habe eine Methode namens GetCurrentUser auf meiner Schnittstelle implementiert, die ein Benutzerobjekt zurückgibt, das ich dann bei Bedarf in meinen Aktionen verwenden kann, indem ich es an die Ansicht übergebe.

using System.Security.Principal; 
using System.Web; 

public interface IUserSession 
{ 
    User GetCurrentUser(); 
} 

public class WebUserSession : IUserSession 
{ 
    public User GetCurrentUser() 
    { 
     IIdentity identity = HttpContext.Current.User.Identity; 
     if (!identity.IsAuthenticated) 
     { 
      return null; 
     } 

     User currentUser = // logic to grab user by identity.Name; 
     return currentUser; 
    } 
} 

public class SomeController : Controller 
{ 
    private readonly IUserSession _userSession; 

    public SomeController(IUserSession userSession) 
    { 
     _userSession = userSession; 
    } 

    public ActionResult Index() 
    { 
     User user = _userSession.GetCurrentUser(); 
     return View(user); 
    } 
} 

Wie Sie sehen können, haben Sie jetzt Zugriff, um den Benutzer bei Bedarf abzurufen. Natürlich können Sie die GetCurrentUser-Methode ändern, um zuerst in die Sitzung oder andere Mittel zu schauen, damit Sie nicht ständig in die Datenbank gehen.

2

Jeff,

Wie ich schon sagte in einem Kommentar zu Ihrer Frage oben, Sie muss die ClaimedIdentifier für den Benutzernamen verwenden - das heißt, den ersten Parameter zu SetAuthCookie. Es gibt einen großen Sicherheitsgrund dafür. Fühlen Sie sich frei, einen Thread auf [email protected] zu starten, wenn Sie mehr über die Gründe erfahren möchten.

Jetzt in Bezug auf Ihre Frage zu einem gesamten Benutzerobjekt ... Wenn Sie das als Cookie senden möchten, müssten Sie Ihr Benutzerobjekt als Zeichenfolge serialisieren, dann müssten Sie es in einigen signieren Möglichkeit zum Schutz vor Manipulation durch den Benutzer. Vielleicht möchten Sie es auch verschlüsseln. Blah, es ist eine Menge Arbeit, und du würdest mit einem großen Cookie enden, der mit jeder Web-Anfrage, die du nicht willst, hin und her geht.

Was ich in meinen Apps mache, um das von Ihnen angegebene Problem zu lösen, ist das Hinzufügen einer statischen Eigenschaft zu meiner Datei Global.asax.cs namens CurrentUser.Wie folgt aus:

public static User CurrentUser { 
    get { 
     User user = HttpContext.Current.Items["CurrentUser"] as User; 
     if (user == null && HttpContext.Current.User.Identity.IsAuthenticated) { 
      user = Database.LookupUserByClaimedIdentifier(HttpContext.Current.User.Identity.Name); 
      HttpContext.Current.Items["CurrentUser"] = user; 
     } 
     return user; 
    } 
} 

Hinweis cachen ich das Ergebnis im HttpContext.Current.Items Wörterbuch, das zu einer HTTP-Anforderung spezifisch ist, und hält der Benutzer zu einem einzigen Treffer herunterzuholen - und holt es nur die Das erste Mal, wenn eine Seite die CurrentUser-Informationen tatsächlich möchte.

So eine Seite leicht Strom in Benutzerinformationen wie dies protokolliert werden können:

User user = Global.CurrentUser; 
if (user != null) { // unnecessary check if this is a page that users must be authenticated to access 
    int age = user.Age; // whatever you need here 
} 
+0

Ich werde das untersuchen. Ich habe gestern 8 Stunden damit verbracht, meinen eigenen MembershipProvider zu erstellen. In ein paar Stunden werde ich updaten. Dieser Weg ist viel einfacher als gestern. Ich mag auch, was ich hier sehe. –

+0

Ich denke, dass das ist, was ich gehen werde. Es fügt sich direkt in das ein, was ich habe und erfordert nur den einen Anruf, wie du es erwähnst. Ich könnte das sehr gut ohne den Custom Provider überhaupt mit der von dir beschriebenen Methode machen. Vielen Dank. –

+0

Froh, dass es für Sie funktioniert. Ich finde, dass der asp.net-Mitgliedschaft-Anbieter eine sehr schlechte Passform für Redirect-basierte, passwortlose Authentifizierungsprotokolle wie OpenID ist. Jeder Mitgliedschaftsanbieter, der mit OpenID arbeitet, kann aufgrund der Schnittstelle, die einfach nicht gut passt, nur auf halbem Wege implementiert werden. –