6

Używam bagażnik wiosna, a ja umożliwiły globalne bezpieczeństwo metody w WebSecurityConfigurerAdapter przezJak @PreAuthorize mające wyższy priorytet niż @Valid lub @Validated

@EnableGlobalMethodSecurity(prePostEnabled = true, order = Ordered.HIGHEST_PRECEDENCE) 

I Poniżej jest mój kod kontrolera

@PreAuthorize("hasAnyRole('admin') or principal.id == id") 
@RequestMapping(value = "/{id}", method = RequestMethod.PUT) 
public User updateUser(@PathVariable("id") String id, @Valid @RequestBody UserDto userDto) 
{ ....} 

Jednak, gdy użytkownik niebędący administratorem próbuje wykonać żądanie PUT, walidator JSR303 zostanie uruchomiony przed @PreAuthorize. Na przykład użytkownik, który nie jest administratorem, otrzymywał coś w stylu "imię jest wymagane" zamiast "odmowa dostępu". Ale po podaniu przez użytkownika pierwszej zmiennej imienia, aby przekazać walidator, zwracano odmowę dostępu.

Czy ktoś wie, jak wymusić sprawdzenie @PreAuthorize przed sprawdzeniem @Valid lub @Validated?

I muszę użyć tego rodzaju autoryzacji na poziomie metody zamiast autoryzacji opartej na adresach URL, aby przeprowadzić pewne skomplikowane sprawdzanie reguł.

+1

To się nigdy nie zdarzy. '@ PreAuthorize' jest wywoływany tylko podczas wykonywania metody. Jednak "@ Valid" jest przetwarzany podczas przygotowywania wykonania metody, co dzieje się przed faktycznym wykonaniem metody. To nie zadziała. Podczas pracy możesz wykonywać ręczne sprawdzanie poprawności, zamiast polegać na adnotacji "@ Valid". –

+0

Rozumiem. Dziękuję za wyjaśnienie, jak to działa w tle. Myślę, że byłoby wspaniale, gdyby w przyszłości mogli wspierać walidację po PreAuthorize. – user2763165

+0

To byłoby trudne, ponieważ mogłoby to zmienić cały sposób działania AOP :).Widzę poprawę w zakresie mapowania adresów URL i dodawania do nich zabezpieczeń. Obecnie używane są tylko wyrażenia w stylu mrówki i wyrażenia regularne, ale widzę, że można chcieć użyć zmiennych ścieżkowych również dla bezpieczeństwa. –

Odpowiedz

0

W tym samym scenariuszu znalazłem zalecenia dotyczące wdrożenia zabezpieczeń za pomocą filtrów sprężynowych.
Oto podobny wpis: How to check security acess (@Secured or @PreAuthorize) before validation (@Valid) in my Controller?

Ponadto, może inne podejście - spróbuj użyć walidacji poprzez rejestracji niestandardową walidatora w @InitBinder (zatem pominąć @valid adnotacji).

Aby uzyskać dostęp do głównego przedmiotu w klasie filtra:

SecurityContextImpl sci = (SecurityContextImpl)  
session().getAttribute("SPRING_SECURITY_CONTEXT"); 

if (sci != null) { 
    UserDetails cud = (UserDetails) sci.getAuthentication().getPrincipal(); 

} 

W tym przypadku/{id} jest param ścieżki w adresie URL. Aby uzyskać dostęp do parametrów ścieżki w klasie filtra lub przechwytywania:

+1

Dzięki, zobaczyłem również, że post, ale filtry sprężynowe (oparte na adresie URL) nie będą działać w moim przypadku, ponieważ muszę sprawdzić poprawność względem głównego identyfikatora z parametrami adresu URL. I używam @ InitBinder w mojej implementacji, ale @ PreAuthorize nadal nie jest wywoływana przed walidatorem. – user2763165

+0

można uzyskać dostęp do obiektu głównego w filtrze serwletów. Czy to pomaga? –

+0

Dodałem urywek, który uzyskuje dostęp do obiektu głównego w klasie filtru serwletów. Nie jestem pewien, czy to ułatwi ... –

1

Miałem ten sam problem i znalazłem ten wpis. Komentarz M. Deinum pomaga mi zrozumieć, co się dzieje źle

Oto co zrobiłem:

  1. Metoda publiczna ma @PreAuthorize i zrobić Skontrolować
  2. Istnieje NO @ Poprawne w parametrze @RequestBody
  3. Tworzę drugą metodę, prywatną, gdzie I do zatwierdzenia DTO. Korzystanie z adnotacji @Valid
  4. Publiczne metody przekazują połączenie do prywatnego. Prywatna metoda jest wywoływana tylko jest metoda publiczna jest upoważniony

Przykład:

@RequestMapping(method = RequestMethod.POST) 
@PreAuthorize("hasRole('MY_ROLE')") 
public ResponseEntity createNewMessage(@RequestBody CreateMessageDTO createMessageDTO) { 
    // The user is authorized 
    return createNewMessageWithValidation(createMessageDTO); 
} 

private ResponseEntity createNewMessageWithValidation(@Valid CreateMessageDTO createMessageDTO) { 
    // The DTO is valid 
    return ... 
} 
+0

wydaje się obejść, ale nie działa. –