+-
Spring Session Redis和Spring Security如何更新用户会话?
我正在使用 spring boot, spring secuirity和spring session(redis)构建一个 Spring REST Web应用程序.我正在使用spring cloud和zuul proxy建立一个遵循网关模式的云应用程序.在这种模式中,我使用spring会话来管理redis中的HttpSesssion并使用它来授权我的资源服务器上的请求.当执行一个改变会话权限的操作时,我想更新该对象,以便用户不必注销以反映更新.有人有解决方案吗?
最佳答案
要更新权限,您需要在两个位置修改身份验证对象.一个在安全上下文中,另一个在请求上下文中.您的主要对象是org.springframework.security.core.userdetails.User或扩展该类(如果您已重写UserDetailsS​​ervice).这适用于修改当前用户.

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所以我只是将我的过滤器改为1,以确保它是下一个被执行的过滤器.

工作流程如下:

>修改用户权限
>发送消息进行过滤
>添加用户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); }
点击查看更多相关文章

转载注明原文:Spring Session Redis和Spring Security如何更新用户会话? - 乐贴网