2012-12-12 10 views
8

Meine MVC-Anwendung verwendet die Rolle eines Benutzers an mehreren Stellen während einzelner Seitenanforderungen. Meine Frage ist, ob der Standard-SqlRoleProvider die aktuellen Benutzerrollen für die Lebensdauer einer Seitenanforderung zwischenspeichert?Wird der Rollenanbieter pro Anfrage zwischengespeichert?

Zum Beispiel habe ich die Verwendung von Rollen in Attributen auf Controller-Methoden machen:

[Authorize(Roles = "Admin")] 

und benutzerdefinierten Code

if (user.IsInRole(MembershipRole.Admin)) 
{ 
    // Do something 
} 
else if (user.IsInRole(MembershipRole.Printer)) 
{ 
    // Do something else 
} 

Wenn die Rolle Provider nicht Rollen zwischenzuspeichern, ist die beste Lösung zu schreiben ein benutzerdefinierter Rollenanbieter, der von dem Standardrollenserver erbt und die Methoden überschreibt, um die Rollen einmal zu erhalten und sie für die Dauer der Anforderung zwischenzuspeichern? Kann dies so geschehen, dass sowohl das Autorize-Attribut als auch mein eigener Code die zwischengespeicherten Rollen nutzt?

(Falls Sie sich wundern, ich möchte nicht die cacheRolesInCookie web.config Option verwenden, um die Rollen in Cookies zwischenzuspeichern).

Vielen Dank im Voraus für Anregungen.

[Edit Details von Joe Antwort ausgelöst schließen]

I dekompilierten System.Web.Mvc.AuthorizeAttribute und die AuthorizeCore Methode die folgende Methode ruft für jede Rolle zu überprüfen:

httpContext.User.IsInRole 

Wenn Sie dann in System.Web.Security.RolePrincipal schauen (was "Benutzer" oben ist), verwenden beide Methoden tatsächlich eine zwischengespeicherte Kopie der Benutzerrollen (oder füllen den Cache, wenn sie leer sind):

Der Cache wird als Feld auf Benutzer gespeichert, so dass seine Lebensdauer für die Dauer der Anforderung gilt. mit

Die Verfahren finden die Rollen:

Roles.Providers[this._ProviderName].GetRolesForUser(this.Identity.Name) 

wird so verwenden, was Rollenanbieter Sie für die Anwendung gewählt haben (default oder custom).

Antwort

6

Wenn Sie ein RoleProvider in einer ASP.NET oder ASP.NET MVC-Anwendung zu verwenden, dann wird HttpContext.User ein RolePrincipal verweisen, die Cache tut Rollen für die gesamte Lebensdauer des Antrags.

jedoch in einem WCF-Dienst, die ASP.NET-Rollen verwendet:

<behavior ...> 
    <serviceAuthorization principalPermissionMode ="UseAspNetRoles" 
        roleProviderName ="MyRoleProvider" /> 
</behavior> 

das ist nicht wahr: Statt HttpContext.User wird verweisen auf die interne Klasse System.ServiceModel.Security.RoleProviderPrincipal, die keine Rollen zwischenspeichert: Statt ruft immer RoleProvider.IsUserInRole.

Die sofort einsatzbereiten RoleProvider führen kein Caching durch. Dies kann zu wiederholten Verbindungen mit dem zugrunde liegenden Datenspeicher führen. Es scheint mir ein Mangel zu sein: Es wäre einfach gewesen, die Rollen beim ersten Zugriff zu cachen.

ist die beste Lösung zum Schreiben eines benutzerdefinierten Rollenanbieters, der von der Standardrolle erbt und überschreibt die Methoden zum einmaligen Abrufen der Rollen und zum Zwischenspeichern für die Anforderungsdauer?

Nicht erforderlich für ASP.NET oder ASP.NET MVC, könnte aber für WCF ins Auge gefasst werden. Caching für die Request-Dauer verwendet vermutlich HttpContext.Items, so dass eine Abhängigkeit von der Existenz von HttpContext eingeführt wird, aber das ist nicht notwendigerweise ein Problem, außer dass Unit-Tests schwieriger werden.

Kann dies so erfolgen, dass sowohl das Autorize-Attribut als auch mein eigener Code die zwischengespeicherten Rollen nutzt?

Wenn Sie Ihre benutzerdefinierten RoleProvider in web.config konfigurieren gibt es nichts mehr Sie tun müssen, so dass die Authorize Attribut sie verwenden.

+2

Vielen Dank für Ihre Gedanken. Die MSDN-Dokumentation zu RolePrincipal sagt: "Wenn CacheRolesInCookie false ist, sucht das RolePrincipal-Objekt immer die Rollenmitgliedschaft mithilfe des Rollenanbieters." Wenn Sie sagen, RolePrincipal "caches Rollen für die Lebensdauer der Anfrage" kann ich fragen, wie Sie das wissen (Reflexion, SQL-Profiling, Dokumentation, etc.), wie es MSDN widersprechen scheint? – Appetere

+0

@Steve, das weiß ich, indem ich mir die Implementierung (Lutz Reflector oder ILSpy) anschaue und auch die Erfahrung bei der Implementierung von Custom Providern. Dies widerspricht nicht MSDN: RolePrincipal sucht nach Rollenmodulen unter Verwendung des Rollenanbieters - es ruft RoleProvider.GetRolesForUser auf, ruft sie jedoch nur einmal pro Anforderung auf und speichert das Ergebnis in einem HybridDictionary-Feld. Der RoleProviderPrincipal von WCF ruft RoleProvider.GetRolesForUser nicht auf, sondern ruft immer RoleProvider.IsInRole auf und implementiert kein Zwischenspeichern von Rollen. – Joe

+0

Danke dafür. Ich folgte Ihrem Ansatz und dekompilierte die relevanten Assemblys, um zu sehen, was tatsächlich passiert. Einige Details zu meiner ursprünglichen Frage hinzugefügt, um sie der Antwort hinzuzufügen. – Appetere