luchob/softuni-feb2023

Проблем с използването на @PreAuthorize

Closed this issue · 9 comments

Привет! Опитвам се да използвам спринг секюрити, за да разреша на логнат потребител да трие и променя съдържанието, което е генерирал(например своя оферта). Видях, че в ведно от ишутата сте коментирали същата тема с един колега. Следвам стъпките, но в контролера не ми се резолва @PreAuthorize("isOwner(#id)") и явно пропускам нещо някъде.

Това ми е сървиса
image

Тук ми е имплементация на MethodSecurityExpressionOperations в която метода isOwner стои неактивен и не се използва
image

Следва SecurityExpressionHandler
image

Кофигурацията с новата анотация @EnableMethodSecurity
image

И в контролера "вълшебния" метод, както го наричаш стои неизползваем
image

Поздрави и успешен ден от мен! :)

luchob commented

Привет!

А има ли го някъде комитнато това, предпочитам кода пред снимка на кода ;-)

Поздрави,
Л.

Привет отново!
Да, извинявам се, пропуснах да сложа и линк - https://github.com/MilenaDimova/real-estate-project

Поздрави! :)

luchob commented

Ок, благодаря, после ще го видя!

Поздрави,
Л.

luchob commented

За съжаление, това нещо няма да работи в новия спринг, поради промените в DefaultMethodSecurityExpressionHandler. Опитах да екстендвам AbstractSecurityExpressionHandler но е доста тегаво и вече не съм сигурен че е удачно решение. :-) На този момент не мога да му отделя достатъчно време, така че ти предлагам едно малко по... дървенко но все пак нелошо решение. Може в @PreAuthorize да викаш метод на бийн. Така:

    @PreAuthorize("@offerService.isOwner(#principal.name, #uuid)")
    @DeleteMapping("/offers/{id}")
    public String deleteOffer(
        Principal principal,
        @PathVariable("id") UUID uuid) {
        ...
    }

По натам ще му отделя малко повечко време. И без това трябва да мигрираме някакви сървиси на Спринг 3 и оттам съм черпил вдъхновение :))) Като имам повечко информация може да пиша тук. Остава изводът, че трябва да се внимава повечко при наследяване на спринговски класове, които не са абстрактни. Иначе боли в даден момент... :(

Поздрави,
Л.

Добре, връщам се на предния вариант, поне е работещ :) Предполагам сега в SecurityConfiguration класа трябва да сложа новата анотация - @EnableMethodSecurity вместо @EnableGlobalMethodSecurity(prePostEnabled = true)?

Благодаря за бързата реакция! Ще следя за инфо по въпроса тук.

Поздрави,
Милена Димова

luchob commented

Мисля, че си ок с EnableGlobalMethodSecurity:

EnableGlobalMethodSecurity provides AOP security on methods. Some of the annotations that it provides are PreAuthorize, PostAuthorize.

Другото е за настройки с http security-то в конфига. Да видим и ние в работата какво ще правим тези дни с това "проблемче" :-)

Поздрави,
Л.

Не става с @EnableGlobalMethodSecurity защото е деприкейтед. Направих си няколко експеримента и без никаква допълнителна анотация в SecurityConfiguration класа, @PreAuthorize("@offerService.isOwner(#principal.name, #id)") спира да работи и трие всички оферти независимо от ролята на логнатия потребител. В случая с @EnableMethodSecurity, делийта работи, както се очаква, но спира да ми работи offerService-а в контролера и ми излиза, че offerService е null. Леко се обърках какво точно се случва... :)

Поздрави!

luchob commented

Хах! Това е най-абсурдната грешка, на която съм попадал в последните 3-4 години :-) Унищожи ми вечерта и лекцията с колегите утре, помощта за останалите колеги и личния живот, но мога да ти обясня какво става. :-))

Значи ползваме @EnableMethodSecurity + @Preauthorize в контролера. Ок, @EnableGlobalMethodSecurity са го деприкейтнали в новото секюрити бля бля бля бля, ноооо... остава голямата загадка, която си формулирала:

спира да ми работи offerService-а в контролера и ми излиза, че offerService е null

Абсолютен шах! Стъпка назад - как работи @PreAuthorize? Тази анотация използва спринг AOP (чувала си за AOP, нали? :-) ) и като я сложиш на контролера той престава да бъде обикновен контролер, а вместо това става CGLIB прокси, както може би си забелязала от дебъгера. Само че по дифоулт CGLIB прокситата не пипат private методите. А ти погрешка си направила @PostMapping-а прайвът:

   @PostMapping("/add")
    private String addConfirm(@Valid OfferAddBindingModel offerAddBindingModel, BindingResult bindingResult,
                              RedirectAttributes redirectAttributes, @AuthenticationPrincipal UserDetails userDetails) {

    }

Скапаният спринг няма абсолютно никакъв проблем да работи с прайвът мапинги без предупреждение. Но когато се намеси и CGLIB AOP proxy... има "offerService е null" тъй като работи върху оригиналния обект, а не върху проксито. Ако го направиш public вече няма да е null ;-)

Яко, ъ? :-)

Поздрави,
Л.

Хах, малее, извинявам се за загубеното време, направо не мога да повярвам каква идиотска грешка съм допуснала :( Сега ще коригирам нещата в проекта. Още веднъж благодаря и дано не ми се сърдят много хора!

Поздрави и лека вечер!