2009-09-10 7 views
10

Powiedzmy, że mam aplikację ASP.Net MVC i ta aplikacja (UI) odwołuje się do warstwy logiki biznesowej (BLL), a BLL odwołuje się do mojej warstwy dostępu do danych (DAL)..Net Członkostwo w aplikacji nTier

Korzystam z usługi Custom Membership and Role Provider dla autoryzacji.

Próbuję określić, jakie warstwy muszą odnosić się do mojego dostawcy członkostwa.

w MVC można przeprowadzić kontrole zezwolenia w następujący sposób:

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

I w moim BLL może chcę sprawdzić, czy użytkownik znajduje się w rolę, a także:

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; 
    } 

Będę musiał odwołać i utworzyć instancję klasy Membership w obu warstwach, jeśli to zrobię. Czy to jest właściwy sposób na zaprojektowanie takiej aplikacji? Wydaje się, że dużo redundancji.

Od kiedy mam BLL, czy należy unikać używania atrybutów "[Authorize (Roles =" SomeRoleName ")]] i zamiast tego wywoływać funkcję BLL z kodu MVC, aby sprawdzić, czy użytkownik jest w roli? Jeśli to zrobię, MVC nadal potrzebuje odniesienia do dostawcy członkostwa w celu uwierzytelnienia i tak czy inaczej, aby skorzystać z logowania i innych formantów ASP, prawda?

Czy jestem daleko od bazy i zmierzam w złym kierunku?

Odpowiedz

4

Moim zdaniem jest to słabość konstrukcji Członkostwo/rolę.

Sposób, w jaki można to obejść, na przykład mieć autoryzację opartą na rolach na poziomach interfejsu użytkownika i BLL w rozproszonej aplikacji n-warstwowej, polegałby na udostępnieniu usługi w warstwie BLL, która eksponuje odpowiednie bity (GetRolesForUser itp.) I jest realizowany przez wywołanie RoleProvider na serwerze.

Następnie zaimplementuj niestandardowego RoleProvider na kliencie zaimplementowanym przez wywołanie usługi odsłoniętej przez BLL.

W ten sposób warstwy warstwy pośredniej i warstwa BLL współdzielą tę samą rolę RoleProvider. Warstwa interfejsu użytkownika może wykorzystywać wiedzę na temat ról bieżącego użytkownika do ulepszania interfejsu użytkownika (na przykład ukrywanie/wyłączanie kontroli interfejsu użytkownika odpowiadających nieautoryzowanym funkcjom), a BLL może zapewnić, że użytkownicy nie mogą wykonywać logiki biznesowej, dla których nie są uprawnieni.

0

Pobierz obiekt użytkownika, aby zaimplementować interfejs IPrincipal i wyrzuć go wokół warstw. Wtedy nadal możesz użyć wbudowanego atrybutu [Autoryzuj].

Pomyślnie napisany ponad 3 lata temu o zamku, this article może pomóc. Zaczyna docierać do rzeczy IPrincipala w połowie drogi.

HTHS
Charles

+0

Zdecydowanie użyj atrybutu Authorize w MVC. Nie musisz ręcznie sprawdzać wartości IsInRoles. –

+0

Problem polega na tym, że muszę przetwarzać dodatkową logikę biznesową oprócz "IsInRole" lub "Authorize", które moim zdaniem powinny zawsze być w BLL. Mogę przekazać obiekt użytkownika wszędzie, ale dlaczego nie po prostu pominąć Authorize i używać tylko BLL. – Jay

1

Doskonałe pytanie, zadałem sobie to samo dzisiaj. Jedną z idei, którą miałem (ale nie jestem do końca pewien, czy to najlepszy sposób, aby przejść) jest użycie interfejsu (np. IRoleProvider), który można przekazać do BLL, aby przetestować swój dostęp.

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

Dzięki temu, nadal weryfikacji dostępu w BLL, można użyć mock w badaniach jednostkowych, aby sprawdzić swoją logikę i po prostu trzeba utworzyć klasę (lub zaimplementować to w klasie baseController) w twoja strona internetowa MVC, która zaimplementuje IRoleProvider i zrobi właściwe sprawdzanie za pomocą API autoryzacji ASP.NET.

Mam nadzieję, że to pomoże.

-1

Dostęp do ról zwykle nie powinien być w BLL. Dostęp to odpowiedzialność za interfejs użytkownika.

W ten sposób wykorzystaj interfejs IPrinciple, o czym wspomniały powyższe plakaty. Masz dostęp do IPrinciple na poziomie wątku.

Thread.CurrentPrincipal 
+0

Charles, thx za odpowiedź. Jak widać, muszę jednak przetworzyć logikę biznesową, inną niż podstawowa kontrola ról, w celu ustalenia, w celu ustalenia prawdziwych zabezpieczeń użytkowników. Doszedłem do wniosku, że wszystkie BL powinny być w BLL, dlatego też planowałem zamknąć tam również bezpieczeństwo. Mówisz, że lepiej jest, jeśli "IsRoleEditor" powyżej znajduje się w mojej warstwie interfejsu użytkownika, a nie w BLL? – Jay

+1

-1 Nie zgadzam się: autoryzacja (przynależność do roli lub jakiś inny mechanizm) jest zdecydowanie obowiązkiem BLL. Warstwa interfejsu użytkownika może być uruchomiona na kliencie (na przykład Winform), więc może zostać naruszona. – Joe

+0

To wszystko zależy od tego, jak projektujesz tę aplikację. Podaj przykład rozwiązania, coś prostego, tylko nazwy projektów i ich wzajemne odniesienia. – dmportella

0

Dlaczego nie przekazać ról do BLL, aby nie mieć żadnej zależności od Członkostwa. Lub użyj interfejsu takiego jak sugerował MartinB.

Co stanie się w przyszłości, gdy interesariusze zdecydują się na inną formę uwierzytelniania i przestaniesz pracować z obiektem Role?

Przykład:

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

Nie brakuje punktu MVC. MVC dzieli naturalność na poziomy. Model (DAL), kontroler (BLL), widok (prezentacja). Mogą one wchodzić w różne projekty, jeśli chcesz, ale ponieważ kontroler ma całą logikę biznesową - potrzebujesz tylko dostępu do roli RoleProvider.

Następnie zastosuj wzorce, takie jak repozytorium, wzór itp., Aby podzielić je dalej, jeśli chcesz.

Davy

+0

Rozumiem koncepcję MVC, ale jeśli ustawię BLL tak, aby zawierał walidację ról, to dlaczego funkcja "[Authorize (Roles =" SomeRoleName ")]" w interfejsie użytkownika? – Jay

+0

@jay Atrybut autoryzacji jest używany w kontrolerze, ponieważ według Davy'ego jest to Warstwa Biznesowa. Myślę, że kieruje się tym, że ignorujesz fakt, że "warstwy" zostały już podzielone przez wzór MVC. Myślę, że to wszystko zależy od tego, jak konstruujesz to rozwiązanie Jay, czy możesz zrobić schemat, aby pokazać nam, jak projektujesz to? – dmportella

+0

Schemat pomoże. Czy masz na myśli capirulity UI jak w widoku? Jeśli tak, to dobrze jest po prostu mieć głupi HTML, ale masz widok, w którym chcesz pokazać coś na podstawie ról, takich jak "autoryzowane pole wyboru", które tylko superwizorzy mogą zobaczyć w widoku innym. Dostęp do ról jest w mojej opinii przydatny. – Davy

0

Aby połączyć kontroler MVC 'UI' jest sposobem chybione .. The 'C' w MVC jest część Twojego BLL, nawet jeśli odwołuje zajęcia, które ty nazwałbym BLL. Jednak nie o to pytasz.

Myślę, że rozwiązałbym ten problem, zadając pytanie: "czy istnieje rzeczywisty wymóg 100% oddzielenia aplikacji" UI "od" BLL "?". Jeśli oba komponenty współdzielą zależność od dostawców elementów/ról, pozwól, aby tak się stało i zacznij działać.

W przypadku odłączania BLL i podłączania nowego, być może posiadanie współdzielonej zależności od dostawcy .NET jest czymś, z czym można żyć. Wiesz, że to chyba ok, a twoja aplikacja może się nie rozpaść.

myślę nad odpowiedzią Joe sprawia, że ​​wiele sensu, choć ...

+1

Nie jestem pewien, czy kontroler jest częścią twojego BLL, w rzeczywistości, myślę, że nie powinien zawierać żadnej logiki biznesowej, tylko orkiestrację pomiędzy twoimi obiektami domeny. –

+0

WTF to logika biznesowa? Cała aplikacja jest logiką biznesową, składającą się z różnych elementów logiki biznesowej. Część logiczna interfejsu użytkownika, część logiki MVC. Posiadanie kodu poprawnie zaprojektowanego i wyodrębnionego jest celem, bez stosowania ogólnych nazw dla złożonych komponentów. . Idea tych prostych warstw liniowych w górę iw dół jest głupia. Diagram rozwiązania to złożona mapa obiektów, a zajmowanie się krzyżowaniem to nasza praca - problem Jaya jest dobry, radzenie sobie z krzyżowaniem w zależnościach będzie fajnym zadaniem. Nadal uważam, że odpowiedź Joe miała sens, a teraz Po prostu krzyczę. – misteraidan

0

myślę co robisz jest w porządku.

Autoryzacja i autoryzacja powinny znajdować się w warstwie usług, która prawdopodobnie jest przekazywana do kontrolerów.

Jeśli kontroler ustawi Principal and Identity, a następnie użyjesz go w kontrolerze za pomocą atrybutów MVC, to brzmi to jak dobry pomysł.

Byłoby miło ukryć dostawcę członkostwa MVC za interfejsem, w ten sposób można go zamienić na dostawcę członkostwa WinForms (na przykład) i byłby w stanie przetestować sterowniki.