我正在使用spring引導,spring安全性和spring會話(redis)構建一個Spring REST Web應用程序。我正在使用Spring雲和zuul代理在網關模式之後構建雲應用程序。在這種模式下,我使用spring會話來管理redis中的HttpSesssion並使用它來授權我資源服務器上的請求。當執行更改會話權限的操作時,我想更新該對象,以便用戶不必註銷以反映更新。有沒有人有這個解決方案?春季會議Redis和Spring Security如何更新用戶會話?
4
A
回答
8
要更新權限,您需要在兩個地方修改認證對象。一個在安全上下文中,另一個在請求上下文中。您的主體對象將是org.springframework.security.core.userdetails.User或擴展該類(如果您重寫了UserDetailsService)。這適用於修改當前用戶。
Authentication newAuth = new UsernamePasswordAuthenticationToken({YourPrincipalObject},null,List<? extends GrantedAuthority>)
SecurityContextHolder.getContext().setAuthentication(newAuth);
RequestContextHolder.currentRequestAttributes().setAttribute("SPRING_SECURITY_CONTEXT", newAuth, RequestAttributes.SCOPE_GLOBAL_SESSION);
要使用彈出會話爲任何登錄用戶更新會話,需要自定義過濾器。過濾器存儲一組已被某個進程修改的會話。消息系統在需要修改新會話時更新該值。當請求具有匹配的會話密鑰時,篩選器將查找數據庫中的用戶以獲取更新。然後它更新會話上的「SPRING_SECURITY_CONTEXT」屬性並更新SecurityContextHolder中的身份驗證。 用戶不需要註銷。當指定過濾器的順序時,它在SpringSessionRepositoryFilter之後很重要。該對象的@Order爲-2147483598,所以我只是更改了我的過濾器,以確保它是下一個被執行的過濾器。
的工作流程是這樣的:
- 修改用戶A管理局
- 信息發送到過濾
- 添加用戶一個會話密鑰設置(在過濾器)
下一次用戶A通過通過過濾器更新他們的會話
@Component @Order(UpdateAuthFilter.ORDER_AFTER_SPRING_SESSION) public class UpdateAuthFilter extends OncePerRequestFilter { public static final int ORDER_AFTER_SPRING_SESSION = -2147483597; private Logger log = LoggerFactory.getLogger(this.getClass()); private Set<String> permissionsToUpdate = new HashSet<>(); @Autowired private UserJPARepository userJPARepository; private void modifySessionSet(String sessionKey, boolean add) { if (add) { permissionsToUpdate.add(sessionKey); } else { permissionsToUpdate.remove(sessionKey); } } public void addUserSessionsToSet(UpdateUserSessionMessage updateUserSessionMessage) { log.info("UPDATE_USER_SESSION - {} - received", updateUserSessionMessage.getUuid().toString()); updateUserSessionMessage.getSessionKeys().forEach(sessionKey -> modifySessionSet(sessionKey, true)); //clear keys for sessions not in redis log.info("UPDATE_USER_SESSION - {} - success", updateUserSessionMessage.getUuid().toString()); } @Override public void destroy() { } @Override protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { HttpSession session = httpServletRequest.getSession(); if (session != null) { String sessionId = session.getId(); if (permissionsToUpdate.contains(sessionId)) { try { SecurityContextImpl securityContextImpl = (SecurityContextImpl) session.getAttribute("SPRING_SECURITY_CONTEXT"); if (securityContextImpl != null) { Authentication auth = securityContextImpl.getAuthentication(); Optional<User> user = auth != null ? userJPARepository.findByUsername(auth.getName()) : Optional.empty(); if (user.isPresent()) { user.get().getAccessControls().forEach(ac -> ac.setUsers(null)); MyCustomUser myCustomUser = new MyCustomUser (user.get().getUsername(), user.get().getPassword(), user.get().getAccessControls(), user.get().getOrganization().getId()); final Authentication newAuth = new UsernamePasswordAuthenticationToken(myCustomUser , null, user.get().getAccessControls()); SecurityContextHolder.getContext().setAuthentication(newAuth); session.setAttribute("SPRING_SECURITY_CONTEXT", newAuth); } else { //invalidate the session if the user could not be found session.invalidate(); } } else { //invalidate the session if the user could not be found session.invalidate(); } } finally { modifySessionSet(sessionId, false); } } } filterChain.doFilter(httpServletRequest, httpServletResponse); }
相關問題
- 1. 春季會議和CORS
- 2. 春季會話Redis序列化器SerializationException
- 3. 如何更改春季會話(redis)cookie名稱?
- 4. 春季會話:更新立即在redis中登錄用戶對象
- 5. 春季安全春季會議:如何禁止更新會話最後訪問時間爲特定請求
- 6. 如何在春季創建新會話?
- 7. 春季服務器/客戶端會話和休眠會話
- 8. 春季安全會議
- 9. 錯誤與春季會議
- 10. 春季會議記住我
- 11. 春季會議範圍
- 12. 春季會議在@Scheduled
- 13. 春季會議被覆蓋
- 14. 如何使用Spring Security控制會話
- 15. 春季會話數據Redis - 從Redis商店獲取有效會話,當前用戶
- 16. 春季會議休息和好的AuthenticationManager
- 17. 使用Redis在春季會話中添加會話銷毀事件
- 18. 如何創建一個春季會議基於用戶屬性
- 19. '春季會議'是否支持'Web會話聚類'?
- 20. 春季更改了會話值
- 21. 如何在春季結束會話3
- 22. 春季MVC處理會話?
- 23. 春季SessionRegistry會話ID
- 24. 春季會話併發
- 25. 春季會話bean管理
- 26. 使用Redis進行春季會話管理
- 27. 春季會議redis的 '命名沒有豆 'springSessionRepositoryFilter' 被定義'
- 28. 春季會議,嵌入式Redis服務器錯誤
- 29. 錯誤啓動春季會議+ redis在碼頭
- 30. 春季會議+春季網絡插座。根據會話ID向特定客戶端發送消息
這個答案幫了我一大堆,謝謝!但請注意:在修改身份驗證之後,您需要將會話屬性設置爲SecurityContextImpl的實例,而不是身份驗證。 – Lev
謝謝@Ceekay,這節省了我的培根!我會同意@Lev,SecurityContext實現似乎是正確的選擇。另外,如果操作的目標是當前登錄的用戶,我會說'RequestAttributes.SCOPE_SESSION'會更合適。 – demaniak
只需添加,在對'SecurityContextHolder.getContext()。setAuthentication(newAuth)'的調用之後,您就可以使用從'SecurityContenxtHolder.getContext()'獲得的上下文來提供給RequestContext更新。 – demaniak