我正在使用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