2009-09-10 8 views
10

Sagen wir, ich habe eine ASP.Net MVC App und diese App (UI) verweist auf eine Business Logic Layer (BLL) und die BLL verweist auf meine Data Access Layer (DAL).. NET Mitgliedschaft in nTier App

Ich verwende einen benutzerdefinierten Mitgliedschafts- und Rollenanbieter für die Autorisierung.

Ich versuche zu bestimmen, welche Schichten auf meinen Mitgliedschaftsanbieter verweisen müssen.

In MVC Sie Berechtigungsprüfungen in der folgenden Art und Weise durchführen können:

[Authorize(Roles = "SomeRoleName")] 
public ActionResult Index() 
{ 
//do something 
} 

Und in meinem BLL kann ich mag überprüfen, um zu sehen, ob ein Benutzer in einer Rolle als auch ist:

public static bool IsRoleEditor(User user, Role userRole) 
    { 
    bool retValue = false; 

    if (user.Application.AppID == UserRole.Application.AppID) 
    { 
     if (Roles.IsUserInRole("ModifyRoles")) 
     { 
      retValue = true; 
     } 


    return retValue; 
    } 

Ich müsste die Mitgliedschaft Klassen in beiden Schichten verweisen und instanziieren, wenn ich dies tue. Ist das der richtige Weg, um eine App so zu erstellen? Scheint wie eine Menge Redundanz.

Da ich eine BLL habe vermeide ich die Verwendung der "[Authorize (Roles =" SomeRoleName ")]" Attribute und rufen Sie stattdessen eine BLL-Funktion aus dem MVC-Code, um zu überprüfen, ob der Benutzer in einer Rolle ist? Wenn ich das tue, benötigt der MVC immer noch einen Verweis auf den Mitgliedschaftsanbieter für die Authentifizierung und so, um die Login- und andere ASP-Steuerelemente trotzdem zu nutzen, richtig?

Bin ich weg von der Basis und in die falsche Richtung?

Antwort

4

Meiner Ansicht nach ist dies eine Schwäche der Mitgliedschaft/Rollendesign. Die Art, wie ich dies umgehen würde, um beispielsweise eine rollenbasierte Autorisierung sowohl auf UI- als auch auf BLL-Ebenen in einer verteilten n-Tier-App zu haben, wäre, einen Dienst in der BLL-Ebene verfügbar zu machen, der die relevanten Bits freigibt (GetRolesForUser usw.) und wird implementiert, indem der RoleProvider auf dem Server aufgerufen wird.

Implementieren Sie dann einen benutzerdefinierten RoleProvider auf dem Client, der durch Aufrufen des von der BLL bereitgestellten Service implementiert wird.

Auf diese Weise teilen sich die UI-Ebene und die BLL-Ebene den gleichen RoleProvider. Die UI-Schicht kann die Kenntnis der aktuellen Benutzerrollen verwenden, um die UI zu verbessern (z. B. das Ausblenden/Deaktivieren von UI-Steuerelementen für nicht autorisierte Merkmale), und die BLL kann sicherstellen, dass Benutzer Geschäftslogik, für die sie nicht autorisiert sind, nicht ausführen können.

0

Holen Sie sich Ihr Benutzerobjekt, um die IPrincipal-Schnittstelle zu implementieren und diese um die Ebenen zu werfen. Dann können Sie immer noch das eingebaute [Autorize] -Attribut verwenden.

Obwohl geschrieben vor über 3 Jahren und über Burg, kann this article helfen. Es beginnt auf halbem Weg in das IPrincipal-Zeug zu kommen.

HTHS
Charles

+0

Verwenden Sie das Autorize-Attribut in MVC. Sie müssen IsInRoles nicht manuell überprüfen. –

+0

Das Problem ist, dass ich zusätzliche Business-Logik zusätzlich zu "IsInRole" oder "Authorize", die ich dachte, sollte immer in der BLL sein müssen. Ich könnte das Benutzerobjekt überall weitergeben, aber dann warum nicht einfach die Autorisierung weglassen und nur die BLL verwenden. – Jay

1

Ausgezeichnete Frage, fragte ich mich, die heute Gleiche. Eine der Ideen, die ich hatte (aber ich bin mir nicht sicher, ob es der beste Weg ist), ist die Verwendung einer Schnittstelle (zB IRoleProvider), die Sie an Ihren BLL übergeben können, um Ihren Zugriff zu testen.

public static bool IsRoleEditor(User user, IRoleProvider rp) 
{ 
    return (rp.IsUserInRole(user,"ModifyRoles")); 
} 

Damit Sie noch Ihren Zugang in Ihrem BLL überprüfen Sie einen Mock in Ihren Unit-Tests können Sie Ihre Logik überprüfen und Sie müssen nur eine Klasse (oder implementieren diese in einer Base Klasse) zu schaffen, in Ihre MVC-Website, die IRoleProvider implementiert und die ordnungsgemäße Prüfung mithilfe der ASP.NET-Autorisierungs-API durchführt.

Hoffe, das wird helfen.

-1

Der Rollenzugriff sollte normalerweise nicht im BLL sein. Der Zugriff ist eine Verantwortlichkeit für die Benutzerschnittstelle.

Mit diesem gesagt, Hebel die IPrinciple Schnittstelle wie die oben genannten Plakate angegeben haben. Sie haben Zugriff auf IPrinciple auf der Thread-Ebene.

Thread.CurrentPrincipal 
+0

Charles, danke für die Antwort. Wie Sie sehen können, muss ich jedoch eine andere Geschäftslogik als die grundlegende Rollenprüfung verarbeiten, um festzustellen, um die wahre Sicherheit der Benutzer zu bestimmen. Ich dachte, dass alle BL in der BLL sein sollten, weshalb ich plante, die Sicherheit dort auch einzukapseln. Willst du damit sagen, dass der "IsRoleEditor" oben in meiner UI-Schicht und nicht in einer BLL liegt? – Jay

+1

-1 Ich stimme nicht zu: Autorisierung (ob Rollenzugriff oder ein anderer Mechanismus) ist definitiv eine BLL-Verantwortung. Die Benutzeroberflächenebene kann auf dem Client (z. B. Winforms) ausgeführt werden, so dass sie kompromittiert werden kann. – Joe

+0

Es hängt wirklich alles davon ab, wie Sie diese Anwendung gestalten. Gib uns ein Beispiel für deine Lösung, etwas Einfaches, nur Projektnamen und wie sie sich gegenseitig referenzieren. – dmportella

0

Warum nicht die Rollen in Ihre BLL übergeben, so dass Sie keine Abhängigkeit von der Mitgliedschaft haben. Oder verwenden Sie eine Schnittstelle wie MartinB vorgeschlagen.

Was passiert in der Zukunft, wenn sich Ihr (e) Interessenvertreter (n) für eine andere Form der Authentifizierung entscheiden und Sie nicht mehr mit einem Role Objekt arbeiten?

Beispiel:

IsRoleEditor(User user, string[] roles) 
{ 
    return roles.Contains("ModifyRoles"); 
} 
0

Verpassen Sie nicht den Punkt von MVC. MVC spaltet sich natürlich in Tiers auf. Modell (DAL), Controller (BLL), Ansicht (Präsentation). Diese können in verschiedenen Projekten verwendet werden, wenn Sie möchten, aber da der Controller über die gesamte Geschäftslogik verfügt, müssen Sie nur auf den RoleProvider zugreifen.

Dann wenden Sie Muster wie das Repository, Muster usw. an, um weiter zu teilen, wenn Sie wollen.

Davy

+0

Ich verstehe das Konzept von MVC aber dann, wenn ich die BLL einrichten, um die Rolle Validierung enthalten dann warum die "[Autorize (Roles =" SomeRoleName ")]" -Fähigkeit von innerhalb der UI? – Jay

+0

@jay das Autorize-Attribut wird im Controller verwendet, wie Davy sagte, dass die Business-Schicht wäre. Ich denke, was er treibt, ist, dass Sie die Tatsache zu ignorieren scheinen, dass die "Schichten" bereits durch das MVC-Muster gespalten wurden. Ich denke, alles hängt davon ab, wie Sie diese Lösung strukturieren Jay, könnten Sie ein Diagramm erstellen, um uns zu zeigen, wie Sie das gestalten? – dmportella

+0

Ein Diagramm würde helfen. Meinst du UI-Fähigkeit wie in der Ansicht? Wenn Sie das tun, finde ich es gut, nur dummen HTML-Code zu haben, aber Sie haben eine Ansicht, in der Sie etwas basierend auf Rollen wie eine "autorisierte Checkbox" anzeigen möchten, die nur Supervisor in einer ansonsten geteilten Ansicht sehen können. Es ist meiner Meinung nach nützlich, hier auf Rollen zugreifen zu können. – Davy

0

Um die MVC-Controller ‚UI‘ zu nennen, ist Art und Weise weg von der Markierung .. Das ‚C‘ in MVC Teil Ihrer BLL ist, auch wenn es Klassen verweist, die Sie das nennen würde BLL. Das ist jedoch nicht der Punkt Ihrer Frage.

Ich denke, ich würde dieses Problem lösen, indem ich die Frage stelle: "Gibt es eine echte Anforderung für die 100% ige Trennung Ihrer 'UI' App und Ihres 'BLL'?". Wenn beide Komponenten eine Abhängigkeit von den Member/Role-Providern haben, dann lass es so sein und mach weiter.

In dem Fall, in dem Sie Ihre BLL trennen und eine neue einstecken, können Sie möglicherweise mit einer gemeinsamen Abhängigkeit von einem .NET-Anbieter leben. Du weißt, dass das wahrscheinlich in Ordnung ist und deine App nicht auseinander fallen könnte. obwohl ...

+1

Nicht sicher, dass der Controller Teil Ihres BLL ist. Ich denke, er sollte keine Geschäftslogik enthalten, nur eine Orchestrierung zwischen Ihren Domain-Objekten. –

+0

WTF ist Geschäftslogik überhaupt? Die ganze App ist Business-Logik, bestehend aus verschiedenen Komponenten der Geschäftslogik. Der UI-Teil der Logik, der MVC-Teil der Logik .. Ihr Code richtig aufgebaut und abstrahiert ist das Ziel, nicht generische Namen für komplexe Komponenten . Die Idee dieser geradlinigen linearen Schichten ist dumm. Ein Lösungsdiagramm ist eine komplexe Karte von Objekten, und der Umgang mit Crossover ist unser Job - Jay's Problem ist ein guter, der Umgang mit Cross-Over in Abhängigkeiten wird eine lustige Aufgabe sein. Ich denke immer noch, dass Joes Antwort am sinnvollsten war Ich rufe nur. – misteraidan

0

denke ich Joes Antwort oben viel Sinn macht, ich glaube, was Sie tun, ist in Ordnung.

Die Autorisierung und Authentifizierung sollte innerhalb einer Services-Schicht stattfinden, die möglicherweise an Ihre Controller weitergegeben wird.

Wenn der Controller den Principal und die Identität festlegt und Sie diesen dann über die MVC-Attribute im Controller verwenden, dann klingt das nach einer guten Idee.

Es wäre nett, Ihren MVC-Mitgliedschaftsanbieter hinter einer Schnittstelle zu verbergen, so dass Sie ihn zum Beispiel für einen WinForms-Mitgliedschaftsanbieter austauschen und Ihre Controller testen könnten.