ROLES
Closed this issue · 5 comments
Здравей Лъчо,
Имам един казус и не съм сигурен, как точно да подходя.
Ролите са ми наредени както следва:
ADMIN -> ADMIN, MODERATOR, USER
MODERATOR -> MODERATOR, USER
USER-> USER
Приемаме, че работим с потребител, който е ADMIN и бихме искали да променим ролята на потребител
от MODERATOR на USER. Модераторите в апликацията имат право да виждат определени неща, както да трият и ъпдейтват. Логвам се през два браузъра за да имитирам 2 сесии, в единия логвам ADMIN и в другия MODERATOR.
С админа променям ролята на въпросния модератор, като извиквам следния контролер:
@PatchMapping("/user-edit-role/{userId}")
public String updateUserRole(@PathVariable("userId") Long userId,
RoleTypeEnum role) {
this.adminService.updateUserRole(userId, role);
return "redirect:/admin/user-edit/" + userId;
}
Знам, че трябва да направя нещо, което да инвалидира сесията на потребителя, който е бил модератор и вече е станал обикновен юзър за да го накарам да се логне на ново и да има нова сесия с вече актуалните роли. Понеже докато не се разлогне той може да си цъка, каквото иска, а моята идея е за незабавна промяна.
Ако може малко насока какво е подходящо да се направи? Дали изобщо има начин да го разлогна, предполагам че това е начина?
Благодаря педварително!
Поздрави,
Росен :)
Здравей!
Не съм сигурен дали ще работи и сега нямам време да го тествам, затова ще оставя на теб да провериш и да кажеш дали става.
- Инжектираме всички session registries:
private Set<SessionRegistry> sessionRegistries;
- Доимплементираме следния код (или подобен):
sessionRegistries.forEach(
sr -> {
sr.getAllPrincipals().
stream().
filter(p -> ...).
forEach(sr.getAllSessions(p, true) .forEach(
si-> {
si.expireNow();
sr.removeSessionInformation(si.getSessionId());
}
));
}
);
Поздрави,
Л.
Здравей Лъчо,
Поради някаква причина в SessionRegistry -> getAllPrincipals() няма никой...и не мога да разбера защо, ако може малко насока какво може да го накара да е пълен? За да мога да инджектвам SessionRegistry направих @bean, който да връща new SessionRegistryImpl(); и може би това е причината да не е, но не съм сигурен?
Като допълнение, не точно към тази тема, но пак става дума за разлогване на потребител, дали е достатъчно добро да имам такъв Util за ръчно логаутване на текущо логнатия юзър в определена ситуация?
public class SessionManagementUtils {
public static void logoutUser(HttpServletRequest httpServletRequest) throws ServletException {
httpServletRequest.logout();
SecurityContextHolder.getContext().setAuthentication(null);
SecurityContextHolder.clearContext();
HttpSession httpSession = httpServletRequest.getSession();
Enumeration<String> attributeNames = httpSession.getAttributeNames();
while (attributeNames.hasMoreElements()) {
String attr = attributeNames.nextElement();
httpSession.setAttribute(attr, null);
}
removeCookies(httpServletRequest);
httpSession.invalidate();
}
private static void removeCookies(HttpServletRequest httpServletRequest) {
Cookie[] allCookies = httpServletRequest.getCookies();
if (allCookies != null && allCookies.length > 0) {
for (Cookie cookie : allCookies) {
cookie.setMaxAge(0);
}
}
}
}
И където е необходимо да извиквам SessionManagementUtils.logoutUser(httpServletRequest);
Предварително благодаря!
Поздрави,
Росен Митров
Здравей!
За текущо логнатия юзър е невереоятно, но има конкретна документация в spring security :-) Тук. Предлагам да и се доверим.
Сега за SessionRegistry
-то. Хубаво е, че си направил такъв bean, но в документацията на SessionRegistryImpl
пише:
Default implementation of SessionRegistry which listens for SessionDestroyedEvents published in the Spring application context. For this class to function correctly in a web application, it is important that you register an HttpSessionEventPublisher in the web.xml file so that this class is notified of sessions that expire.
Т.е. имаме две неща.
- Трябва ни някакъв ивент публишър (яхуууу, знаем какво са ивенти в спринг :-) ) който обаче слуша само за
SessionDestroyedEvents
... Т.е. не слуша кога се създават сесии. Окей, го регистрираме както пише:
@Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
@Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
return new HttpSessionEventPublisher();
}
Ако пуснеш, ще видиш че пак няма да работи. Затова да пробваме следващата стъпка.
- След малко гледане и ровене, виждам че може да се добави т.нар. sessionAuthenticationStrategy където састройваш спринг секюрити.
and().
sessionManagement().
sessionAuthenticationStrategy(new RegisterSessionAuthenticationStrategy(sessionRegistry)).
RegisterSessionAuthenticationStrategy
е липсващато нещо за да проработи въпросното реджистри.
Т.е. вече имаме регистри дето работи. Остава като че ли още малко, но сега нямам много време да ровя. Ако имаш време пробвай и пиши, ако не ще има следващ рунд защото Spring Security не е съвсем точно само 1 сървлет филтър, както ви залъгвах :-) :-)
Поздрави,
Л.
В допълнение искам да отбележа, че в SessionInformation
е загатнато:
This is primarily used for concurrent session support.
Преведено означава, че експирейшън статуса на SessionInformation
се следи само от ConcurrentSessionFilter
-а, който се активира по подобен начин:
and().
sessionManagement().
sessionAuthenticationStrategy(new RegisterSessionAuthenticationStrategy(sessionRegistry)).
sessionConcurrency(session -> session.maximumSessions(5)). <-- !
Демек той следи за сесиите през SessionRegistry-то. Т.е. няма да логаутнеш юзъра "веднага" а по-скоро ще се случи това при първия му рикуест към сървъра. Като крайния резултат е еднакъв.
Л.
И понеже допускам, че ще ме попиташ как да редиректнем към логин страницата като експайрне сесията... :-) Може са предложа нещо такова.
sessionConcurrency(conf -> {
conf.maximumSessions(5);
conf.expiredUrl("...");
})
Уау :-)
Поздрави,
Л.