Czy kontrola modelu powinna odbywać się w modelu lub kontrolerze? A kto powinien obsługiwać sprawdzanie uprawnień, obiekt użytkownika lub pomocnika UserManagement?
Gdzie to się powinno stać?
Sprawdzanie w kontrolerze:
class MyController {
void performSomeAction() {
if (user.hasRightPermissions()) {
model.someAction();
}
}
...
Kontrola w kontrolerze ułatwia wykonywanie modeli przez proste działania, dzięki czemu możemy zachować całą logikę dla kontrolerów.
Sprawdzanie w modelu:
class MyModel {
void someAction() {
if (user.hasRightPermissions()) {
...
}
}
...
Umieszczając kontrole w modelu, komplikujemy model, ale również upewniamy się, że przypadkowo nie pozwalamy użytkownikom robić rzeczy, których nie powinni robić w kontrolerze.
A przez kogo?
Po osiedleniu się na miejscu, kto powinien przeprowadzać kontrole? Użytkownik?
Class User {
bool hasPermissions(int permissionMask) {
...
}
...
Ale tak naprawdę nie jest obowiązkiem użytkownika wiedzieć, do czego on lub ona może uzyskać dostęp, więc może jakaś klasa pomocnicza?
Class UserManagement {
bool hasPermissions(User user, int permissionMask) {
...
}
...
Wiem, że często zadaje się tylko jedno pytanie, no cóż, ale myślę, że można na nie razem dobrze odpowiedzieć.
źródło
Bezpieczeństwo jest zagadnieniem przekrojowym, dlatego należy je wdrażać w wielu warstwach. Poniżej znajduje się przykład dla MVC, ale koncepcja ma zastosowanie do innych architektur i / lub wzorców, wystarczy zidentyfikować punkty egzekwowania.
Gdzie to się powinno stać?
Widoki mogą zawierać elementy interfejsu użytkownika (widżety, przyciski, menu itp.), Które muszą być wyświetlane lub nie dla niektórych użytkowników, na podstawie ich uprawnień. Może to być obowiązkiem silnika widoku , ponieważ nie chcesz, aby każdy widok sam sobie z tym poradził. W zależności od rodzaju elementów, na których przeprowadzasz autoryzację, przenieś tę odpowiedzialność w inne miejsce. Pomyśl na przykład o menu, w którym niektóre elementy muszą być wyświetlane, a niektóre nie. Elementy można gdzieś zaimplementować jako listę i filtrować tę listę na podstawie uprawnień, a następnie przesłać ją do widoku.
Kontrolery odpowiadają na żądania, więc jeśli użytkownik nie ma uprawnień do wykonania akcji, należy ją sprawdzić przed wywołaniem akcji, przenosząc odpowiedzialność na wywołującego akcję zamiast trzymać ją w kontrolerze. Ma to tę zaletę, że utrzymuje kontroler w czystości, a jeśli coś zmieni się w uprawnieniach, nie musisz przesiewać kontrolerów, aby zastosować te zmiany.
Zasoby są wyświetlane na podstawie uprawnień. Zwykle odbywa się to na poziomie bazy danych , ponieważ nie chcesz wyciągać wszystkiego z bazy danych, a następnie stosować uprawnień.
Jak widać, w zależności od tego, co chcesz autoryzować, istnieją różne miejsca, w których należy to zrobić. Celem jest zachowanie jak najmniej dyskretnej postawy, dzięki czemu przy zmianie polityki bezpieczeństwa możesz ją łatwo zastosować, najlepiej bez zmiany kodu aplikacji. Może to nie dotyczyć małych aplikacji, w których zestaw uprawnień jest dość mały i nie zmienia się zbyt często. Jednak w aplikacjach dla przedsiębiorstw historia jest zupełnie inna.
Kto powinien to zrobić?
Najwyraźniej nie model. Każda warstwa powinna mieć punkt egzekwowania, który obsługuje autoryzację. Kursywą powyżej zaznaczono możliwy punkt egzekwowania dla każdego poziomu.
Spójrz na XACML . Nie musisz go wdrażać w obecnej postaci, ale da ci wskazówki, którymi możesz się kierować.
źródło
Używam następującego schematu. Warto powiedzieć, że większość kontroli uprawnień użytkowników można podzielić na dwa ogólne przypadki:
Dostęp do akcji kontrolera bez sprawdzania atrybutów jest zwykle implementowany w ramach MVC. To jest w ogóle proste: definiujesz reguły, twoi użytkownicy mają rolę. Po prostu sprawdzasz, czy użytkownik ma uprawnienia do wyszukiwania akcji, sprawdzając swoją rolę w regułach.
Dostęp użytkownika do konkretnego modelu powinien być zdefiniowany w modelu. (Aktor jest podstawową klasą użytkownika. Załóżmy, że może to być klient, sprzedawca lub gość).
Umieszczenie tej logiki w modelu przynosi pewien zysk. Metodę kontroli dostępu można dziedziczyć, nie trzeba tworzyć żadnych dodatkowych klas, można korzystać z ogólnych zalet OOP.
Następnie, aby uprościć sprawdzanie dostępu, przyjmujemy pewne założenia, które prawie zawsze są wdrażane już dla uproszczenia i dobrego stylu:
Przy tych założeniach akcje, które używają identyfikatora modelu mogą być powiązane z konkretną instancją modelu. W rzeczywistości większość działań można łatwo przekształcić i przenieść zgodnie z założeniami podanymi powyżej.
Następnie należy zdefiniować i odziedziczyć podstawową klasę abstrakcyjnego kontrolera.
Możesz wywołać metodę SomeController :: checkModelAccess ($ id), kiedy konstruujesz swoje menu i decydujesz, czy pokazać jakiś link.
źródło
Zarówno w modelu, jak i widoku
W widoku - ponieważ interfejs użytkownika nie powinien pokazywać elementów interfejsu użytkownika, które są ograniczone do bieżącego użytkownika
(np. powiedzmy, że przycisk „Usuń” powinien być pokazywany osobom z odpowiednimi uprawnieniami)
W modelu - ponieważ Twoja aplikacja prawdopodobnie ma jakiś interfejs API, prawda? Interfejs API musi również sprawdzać uprawnienia i prawdopodobnie ponownie używa modelu.
(np. masz przycisk „Usuń” w interfejsie użytkownika i metodę interfejsu API „http: / server / API / DeleteEntry / 123” w tym samym czasie
źródło
MVC to wzorzec prezentacji. Jako taki widok i administrator powinien ponosić odpowiedzialność wyłącznie za prezentację. Niektóre uprawnienia dotyczą prezentacji, np. Tryb ekspercki, eksperymentalne funkcje interfejsu użytkownika lub różne projekty. Mogą być obsługiwane przez kontroler MVC.
Wiele innych rodzajów uprawnień ma zastosowanie na kilku warstwach aplikacji. Na przykład, jeśli chcesz mieć użytkowników, którzy mogą tylko przeglądać dane, a nie zmieniać rzeczy:
W tym podejściu występuje pewne powielanie. Ale ponieważ prezentacja jest zwykle niestabilna, można uzasadnić sprawdzenie uprawnień w zwykle bardziej stabilnej części aplikacji, nawet jeśli oznacza to pewne zbędne kontrole w przypadku, gdy warstwa prezentacji działa zgodnie z przeznaczeniem.
źródło