Laden...

MVC: Welcher MembershipProvider ist geeignet?

Erstellt von Abt vor 10 Jahren Letzter Beitrag vor 10 Jahren 1.357 Views
Hinweis von gfoidl vor 10 Jahren

Abgeteilt von MVC4 frage zur Klasse Membership

Abt Themenstarter:in
16.835 Beiträge seit 2008
vor 10 Jahren

Coffeebean, nutzt Du wirklich den (Simple)MembershipProvider?
Dann bist Du ehrlich gesagt der erste, den ich kenne, der dieses (unflexible) Konstrukt produktiv verwendet.

Warum ich diese Provider unflexibel nenne?* Ich habe keine Chance, den Salt des Passworts zu bestimmen und im optimalen Falle dynamisch zu halten.

  • Ich muss den Zugang bzgl. die Implementierung hart in den Code schreiben (WebSecurity-Implementation).
  • Ich muss auf klassische SQL Datenbanken zurück greifen. WebSecurity kommt mit NoSQL nicht klar; und auch keine Chance dies zu beeinflussen.
  • Der alte MembershipProvider hat zahlreiche Fehler, wie zB dass ein ValidateUser ein true zurück gibt, obwohl ein Account gesperrt ist. Gegen solche Fehler kann man sich nicht schützen und man kann sie nicht beeinflussen. Man sitzt da und heult wenn so etwas auftritt.
  • Für RIAs und CMS-Systeme inkl. Caching sind diese Provider dahingehend einfach ungeeignet.

Oder siehst Du das anders?
Ich persönlich sehe keine Vorteile in der realen Welt - nur Nachteile und rate daher dringend davon ab, diese Provider zu verwenden.

6.911 Beiträge seit 2009
vor 10 Jahren

Hallo Abt,

rate daher dringend davon ab, diese Provider zu verwenden.

Welchen Provider würdest du empfehlen (in Bezug auf Forms-Authentifizierung)?

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

Abt Themenstarter:in
16.835 Beiträge seit 2008
vor 10 Jahren

Ehrlich gesagt: gar keinen 😉

Ich finde diese Provider eben unflexibel, und das Authorize-Attribut bietet (oft) auch nur ungenügend variable Möglichkeiten.

Beispiel ein Forum.
Es gibt den Status Gast, normaler User und Moderator = 3 Rollen.

Diese Form ist problemlos realisierbar mit dem Prinzip der Provider und dem Authorize-Attribut.
Aber.. ein Moderator soll jetzt nicht global alles Administrieren können, sondern nur einen bestimmten Bereich (zB Web).
Diese Granularität funktioniert schon nicht mehr mit der von MS zur Verfügung gestellten Infrastruktur.

Ich beiß aktuell also leider in den sauren Apfel, weil ich noch keine Lösung gefunden habe, diese Feinheiten abzudecken.
Bei mir sieht das aktuell leider so aus - und zwar in (fast) jeder Action:


#region Rechteprüfung
var userHasLocalPrivileges = base.UserHasSystemLevel( UserRole.Or( UserSystemLevel.Admin ) )
|| this.Repositories.ForenRechteDelegatesRepository.UserHasActiveDelegate( this.CurrentUser, currentForenID);

if ( !userHasLocalPrivileges )
{
    return ReturnInsuffientPermission( );
}
#endregion

Dahinter steckt eben zusätzlich ein bisschen MongoDB; für die Rechteverteilung setz ich eigene "Collections" (=Tabellen) ein, sodass die Abfragen performanter sind.
Ein Admin darf alles und dann wird eben geschaut, ob dieser User (in dem Fall der Moderator) die Rechte zu der gewünschten Funktion hat.
Es ist in diesem Fall nicht möglich, dass ein Attribut die Überprüfung durchführt. Meist benutz ich das Resultat dann zusätzlich dazu, um bestimmte URLs bzw. Buttons anzuzeigen, oder nicht:

if ( userHasLocalPrivileges )
{
    viewModel.EditForenbereichUrl = RouteConfig.RouteCache.Get( Url, RouteNames.ForenArea.Edit, new RouteValueDictionary { { "forenID", currentForenID } } );
 }

Genauso setze ich zB auch "Premium-Content" ein, sodass freie User eben die Standard-Funktionen zur Verfügung haben und User, die zahlen, etwas mehr (wie es eben mitlerweile so üblich ist).

6.911 Beiträge seit 2009
vor 10 Jahren

Hallo Abt,

ich verstehe worauf die hinaus willst. Danke.

ein Moderator soll jetzt nicht global alles Administrieren können, sondern nur einen bestimmten Bereich (zB Web).

Dazu bietet sich auch eine weitere Rolle "ModeratorWebOnly" an 😉.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

Abt Themenstarter:in
16.835 Beiträge seit 2008
vor 10 Jahren

Die müsstest Du aber hart kodieren, was Du bei einer dynamischen Umgebung halt nich machen kannst.
In meinem Fall sind das keine Foren, sondern was anderes - und davon eben fast 2500 verschiedene "Bereiche".

2.207 Beiträge seit 2011
vor 10 Jahren

Coffeebean, nutzt Du wirklich den (Simple)MembershipProvider?
Dann bist Du ehrlich gesagt der erste, den ich kenne, der dieses (unflexible) Konstrukt produktiv verwendet.

Ja, im Moment noch. Die von dir genannten Probleme sind mir aber auch schon in den Sinn gekommen, irgendwann werde ich darauf stossen. Im Moment reicht es mir, aber, wie geschrieben, kommt das von dir genannte irgendwann.

In erster Linie fand ich das ganze WebSecurity-Ding cool. Willst du was spezielles, musst dus selber implementieren. Also das gemacht (jetziger Stand). Man gewinnt schon ein wenig an Flexibilität (eigene User-Rollen Tabellen etc.)

Ich finde aber auch, dass, wie gfoidl gesagt hat, man in dem Fall, wenn ein Administrator eben nicht alles können sollte, man "Unterrollen" machen kann. Entsprechende Bereiche gibt man dann nur für entsprechende Rollen frei.

In deinem speziellen Fall ("dynamische Umgebung", "fast 2500 versch. 'Bereiche') hast du aber recht.

Grundsätzlich finde ich den Membership-Ansatz von MVC aber nicht schlecht. Wirds zu speziell ists wie so oft: Man braucht was eigenes 😉

Gruss

Coffeebean

Abt Themenstarter:in
16.835 Beiträge seit 2008
vor 10 Jahren

Ich muss einfach nochmal antworten.. 😁

es ist eben nicht so, dass davon nur "größere" Bereiche betroffen sind: das fängt schon klein an! Auch "einfache" Dinge:

Angenommen man erstellt einen neuen Forenbereich. Was machst Du dann?
Du brauchst für jeden Forenbereich einen eigenen Controller bzw. Area oder Actions, wo Du dann einzeln die hart kodieren Rollen hinterlegst. Völlig unnötig. Kann auch alles dynamisch passieren (= weniger Code und Arbeit).

Willst Du einen neuen Bereich erstellen kannste nich einfach "Neuen Forenbereich" anklicken, sondern musst es eben programmieren.

Ich sehe es eher wie: schön gedacht, MS; aber leider nicht zuende.
Ist ja immer wieder so bei MVC. Wir hattens ja erst mit ViewModels und SubmitModels...

2.207 Beiträge seit 2011
vor 10 Jahren

Du brauchst für jeden Forenbereich einen eigenen Controller bzw. Area oder Actions, wo Du dann einzeln die hart kodieren Rollen hinterlegst.

Das stimmt. jedoch denke ich, wenn du nur 2 Rollen hast (z.B. "User" und "Admin") ist es eben recht komfortabel einach mit dem "Authorize(Roles=..." zu arbeiten.

Alles, was grösser, komplexer wird hast du völlig recht, sind hard codierte Rollen fehl am Platz! Im dynamischen Ansatz hast du alles schön an einem Platz und eine einheitliche Logik, die die Rechte vergibt. Nachvollziehbarer, übersichtlicher und weniger Arbeit.

Ist ja immer wieder so bei MVC. Wir hattens ja erst mit ViewModels und SubmitModels...

Ja, das stimmt 😉. View- und SubmitModels drängen sich mMn jedoch wirklich jeder kleinsten MVC-Anwendung auf. Rollenbereiche nicht unbedingt (bei 2 oder vielleicht nur einer Rolle). Vielleicht erst ab 3 Rollen oder ab solchen Anforderungen, wie schon gesagt "Admin darf nicht alles, sondern nur Teilx, und Teil z, aber nicht Teil y". Dann muss man eben abweichen und selber was machen.

1.346 Beiträge seit 2008
vor 10 Jahren

Ich habe solche dynamischen Reaktionen auf einen oder mehrere Parameter per Attribute gelöst. Ich hatte eine solche Struktur vorgegeben:

Rechte sind hirarchisch angeordnet.

Hauptbereich.Unterbereich.Unterunterbereich

Wenn ein Nutzer oder Gruppe das Recht Hauptbereich.Unterbereich.* hat, hat er alle Rechte in dem Bereich. Ein "*" beduetet so, dass ein Nutzer alle Rechte hat.

Ein Beispiel, was ich nun umsetzen wollte: Servers.[server].Edit. Zum Beispiel für einen Administrationsbereich. Es gibt ann z.B. einen Benutzeraccount, oder eine Gruppe, welche Einstellungen eines Servers ändern darf, aber nicht die anderer. [server] entspricht dann einem Parameter der Action.

Mein Attribut dafür sieht dann so aus:

    public class PermissionAttribute : FilterAttribute, IAuthorizationFilter
    {
        public string[] Pattern { get; set; }

        static Regex _regex = new Regex("\\[(?<value>[^.]+)\\]", RegexOptions.Compiled);

        public PermissionAttribute(params string[] pattern)
        {
            Pattern = pattern;
        }

        public void OnAuthorization(AuthorizationContext filterContext)
        {
            if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
            {
                 // ... Weiterleitung auf Login Seite?
            }


            var pattern = from p in Pattern
                          select _regex.Replace(p, match => GetValue(filterContext, match.Groups["value"].Value));
            

            using (var repository = new PermissionRepository ())
            {
                if (!pattern.Any(a => repository.CheckPermission(filterContext.HttpContext.User.Identity.Name, a)))
                {
                      //Keine Rechte...
                }
            }
        }

        private static string GetValue(AuthorizationContext filterContext, string parameter)
        {
            var value = filterContext.Controller.ValueProvider.GetValue(parameter);
            if (value != null) return value.AttemptedValue;

            return (string)filterContext.ActionDescriptor.GetParameters ().First(a => a.ParameterName == parameter).DefaultValue;
        }
    }

Es ist etwas aufwendig, wenn man auch noch Defaultparameter abdecken will, sonst wär es etwas einfacher.

Das macht es jetzt aber ziemlich einfach und übersichtlich dann die Rechte an die Actions oder Controller zu vergeben:


[Permission("Servers.[server].Edit", "Oder.ein.anders.Recht")]
public async Task<ActionResult> Index(int server)
{
    //...
}

LG pdelvo

W
955 Beiträge seit 2010
vor 10 Jahren

Hi.

Eine andere Möglichkeit könnte Interception/AOP darstellen, das die geeigneten Rechteprüfstrategien mittels IOC/DIC in den Controller injiziert.

Abt Themenstarter:in
16.835 Beiträge seit 2008
vor 10 Jahren

Wurde da auch die Performance bei 5000 Requests / Sekunde bedacht?
Die Regex-Variante hab ich auch überlegt - und fiel da eben durch 😉