2009-05-21 11 views
19

Używam ramek bezpieczeństwa wiosennego.Gdy aktualizuję uprawnienia, nie od razu działa. Muszę zamknąć bieżącego użytkownika (oznacza wylogowanie), a następnie ponownie odwiedzić (znaczy się zalogować) będzie aktualizować pozwolenie użytkownika.Jak natychmiast włączyć uprawnienia po aktualizacji użytkownika w ochronie wiosny?

Czy sposób natychmiastowego włączenia uprawnienia po aktualizacji użytkownika w spring security?

+0

Jedno z możliwych rozwiązań opisano w [Dostosowanie zabezpieczonej sesji w czasie rzeczywistym] (http://spring.io/blog/2009/01/03/spring-security-customization-part-2-adjusting-secured-session- w czasie rzeczywistym) wpis na blogu Spring Source. – Karimchik

+0

Trochę to trwało, ale myślę, że to w końcu zostało wymyślone: ​​ http://stackoverflow.com/q/23072235/42962 – hooknc

Odpowiedz

0

Ponieważ nie dość dostarczyć dokładne dane w swoim pytaniu, zakładam, że masz sytuację, w której:

  1. Jesteś dostarczające UserDetailsService załadować do UserDetails gdy użytkownik próbuje się zalogować
  2. Jako część tej usługi, użytkownik wysyła zapytanie do bazy danych/DAO, aby załadować szczegółowe informacje o uprawnieniach użytkownika, i ustawia nadane uprawnienia na podstawie tej
  3. . Gdy powiesz "Gdy aktualizuję uprawnienia", odnoszące się do aktualizacji uprawnień użytkownika w bazie danych (lub czymkolwiek, w czym przechowujesz dane).

Jeśli tak, to co widzisz jest zgodne z projektem - Spring Security ładuje UserDetails tylko dla użytkownika za pierwszym razem, gdy próbują się zalogować, a następnie przechowuje go w Session od tego momentu. Zasadniczo ma to sens, ponieważ pozwala uniknąć konieczności wykonywania tych samych zapytań dotyczących szczegółów użytkownika w każdym żądaniu. Ponadto uprawnienia użytkownika zazwyczaj nie zmieniają się w ciągu 99,9% ich odwiedzin.

Aby zmienić to zachowanie, może zajść potrzeba dodania polecenia/strony "odświeżania", które uruchomi kod (który będzie trzeba napisać), który będzie ponownie sprawdzał usługę UserDetailsService i zastępował UserDetails w SecurityContext . Nie wierzę, że istnieje jakiś wbudowany sposób, aby to zrobić.

+0

Twoje założenie jest poprawne. Chciałbym wiedzieć, czy istnieją dobre sposoby, aby to zrobić, nie mając ponownie zalogować. Być może mogę zmodyfikować uprawnienia użytkownika, które są przechowywane w bieżącej sesji. Próbuję .. –

0

Można utworzyć własną implementację interfejsu UserDetails, który jest zwracany z mechanizmu uwierzytelniania, który umożliwia dostęp do GrantedAuthorities []. Następnie dodaj nowe uprawnienia bezpośrednio do tego obiektu UserDetails. Możesz napotkać problemy, jeśli użytkownik może jednocześnie otworzyć wiele sesji (lub jeśli wielu użytkowników korzysta z tego samego ogólnego hasła), że nowe uprawnienia będą widoczne tylko w sesji, którą zmieniłeś.

3

Rozwiązanie Gandalf jest poprawne, ale nie kompletne. Aby nowe pozwolenia zostały uwzględnione przez ochronę wiosenną (np. Umożliwić dostęp do stron, które wcześniej nie były dostępne), musisz utworzyć nowy obiekt uwierzytelniania (np. Nowy UsernamePasswordAuthenticationToken) zawierający nową listę uprawnień.

7

Można ustawić alwaysReauthenticate w swojej AbstractSecurityInterceptor jak ten

<bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor"> 
     <property name="alwaysReauthenticate" value="true"/> 
... 
</bean> 

Oczywiście należy zwrócić uwagę, bo 99,9% nie ma potrzeby ponownego uwierzytelniania. Ponieważ uwierzytelnianie może wykorzystywać bazę danych lub coś innego, wydajność może się pogorszyć. Ale zazwyczaj masz pamięć podręczną, jak 2nd Level ze stanem hibernacji, więc ładowanie userdetails za każdym razem powinno być operacją tylko do pamięci we wszystkich przypadkach, w których władze się nie zmieniły.

+1

Jeśli chcę zabezpieczyć metody na ziarnach, czy muszę wprowadzić tę samą zmianę do innego filtru, czy to jest dość? –

+1

ten filtr jest przeznaczony tylko dla żądania internetowego, o ile widzę. jeśli korzystasz z MEthodSecurityInterceptor, możesz samemu wywołać ponowne uwierzytelnianie. Ale jeśli każde wywołanie metody jest poprzedzone sprawdzeniem tego filtru internetowego, ponieważ każde wywołanie metody jest nieco wewnątrz żądania http, powinno być dobrze – Janning

+0

To jest poprawna odpowiedź. Chciałbym tylko dodać, że trzeba włączyć przechwytywacz do konfiguracji bezpieczeństwa przez '' wewnątrz sekcji lub przez właściwość przechwytywania: '< nazwa właściwości = "securityMetadataSource"> ' –

-2

Można spróbować to

SecurityContextHolder.getContext().setAuthentication(SecurityContextHolder.getContext().getAuthentication()); 
+1

Próbowałem tego kodu , ale niestety nie miało to żadnego wpływu. – chelder

2

nie wystarczy zresetować wątku kontekst lokalny, trzeba zaktualizować sesji też:

UserContext userContext = (UserContext) context.getAuthentication().getPrincipal(); 
if (userContext != null && userContext.getUsername() != null) { 
    //This is my function to refresh the user details 
    UserDetailsBean userDetails = getUserDetailsBean(userContext.getUsername()); 
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); 
    if (authentication instanceof UsernamePasswordAuthenticationToken) { 
     UsernamePasswordAuthenticationToken auth = (UsernamePasswordAuthenticationToken) authentication; 
     auth.setDetails(userDetails); 
    } 
    return userDetails; 
} else { 
    throw new ServiceException("User not authenticated"); 
} 
request.getSession().setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext()); 

Przynajmniej w Google AppEngine sesji nie jest odniesienia i modyfikując wątek lokalny nie jest aktualizowany automatycznie, musisz ręcznie session.set swój obiekt.

+0

to nie działało, nawet aktualizując atrybuty sesji –

Powiązane problemy