业务背景: 管理员更改其他用户权限,正好用户在登陆状态下,无法刷新管理员刚赋值的权限,只能退出登录,重新登录才能拥有新权限.
业务需求:管理员更改权限,其他用户不退出登录,可以拥有新权限,动态刷新session
感谢这位博客提供的线索
前提条件需要拥有
@Autowired
SessionRegistry sessionRegistry;
如果找不到SessionRegistry
bean 需要自行注册
/**
* 注册bean sessionRegistry
*/
@Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
配置security http
http
... 省略代码
.and()
.sessionManagement()
// 无效session跳转
.invalidSessionUrl(login)
.maximumSessions(1)
// session过期跳转
.expiredUrl(login)
.sessionRegistry(sessionRegistry())
... 省略代码
定义一个 UserSessionManage
package com.gszcn.hisweb.config.session;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpSession;
import java.util.*;
/**
* 用户存储session
* 一个用户储存多个session 出现一个用户多个地方登录
*/
@Component
@Data
@Slf4j
@CacheConfig(cacheNames = "UserSessionManage")
public class UserSessionManage {
/**
* 用户存储session对象
*/
private Map<String,List<HttpSession>> userHttpSession=new HashMap <>();
/**
* 获取当前在线的session
* @param id
* @return
*/
@Cacheable(key = "#id")
public List<HttpSession> getUserSession(String id) {
List <HttpSession> httpSessions = userHttpSession.get(id);
if(httpSessions==null){
httpSessions=new ArrayList <>();
}
return httpSessions;
}
/**
* 修改缓存
* @param id
* @param userSession
*/
@CachePut(key = "#id")
public List<HttpSession> putUserSession(String id, List<HttpSession> userSession) {
userHttpSession.put(id,userSession);
return userSession;
}
}
然后在定义一个SessionManage
package com.gszcn.hisweb.config.session;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* session管理容器
*/
@Data
@Slf4j
@Component
@CacheConfig(cacheNames = "SessionManage")
public class SessionManage {
@Autowired
UserSessionManage userSessionManage;
/**
* 创建map容器
*/
private Map<String,HttpSession> httpSessionMap=new HashMap <>();
/**
* 创建session
* @param id
* @param session
*/
@Cacheable(key = "#id")
public HttpSession createdSession(String id, HttpSession session) {
httpSessionMap.put(id,session);
return session;
}
/**
* 销毁session
* @param id
*/
@CacheEvict(key = "#id")
public void destroyedSession(String id) {
httpSessionMap.remove(id);
}
/**
* 改变session
* @param oldSessionId
* @param newSessionId
* @return
*/
public void changeSession(String oldSessionId, String newSessionId) {
//查询旧的session
}
/**
* 根据sessionid查询session
*/
@Cacheable(key = "#id")
public HttpSession getSessionID(String id){
return httpSessionMap.get(id);
}
/**
* 当前用户保存session
* @param id 用户id
* @param httpSessions
*/
@Cacheable(key = "'user'+#id",unless = "!#result.contains(#httpSessions)")
public List <HttpSession> putUserSession(String id, HttpSession httpSessions) {
List <HttpSession> userSession = userSessionManage.getUserSession(id);
if(!userSession.contains(httpSessions)){
userSession.add(httpSessions);
}
userSessionManage.putUserSession(id,userSession);
return userSession;
}
}
监听每次的请求防止多账号不同步权限
/**
* 监听Servlet 请求
*/
@Component
class ServletRequestHandledEventListener implements ApplicationListener <ServletRequestHandledEvent> {
@Override
public void onApplicationEvent(ServletRequestHandledEvent event) {
log.info("ServletRequestHandledEventListener:{}",event);
String sessionId = event.getSessionId();
SessionInformation sessionInformation = sessionRegistry.getSessionInformation(sessionId);
if(sessionInformation==null){return;}
Object principal = sessionInformation.getPrincipal();
try {
if(principal instanceof SysUser){
SysUser user = (SysUser) principal;
sessionManage.putUserSession(user.getId(),SecurityUtil.getHttpSession());
}
} catch (Exception e) {
log.warn("当前无法监听到用户信息");
}
}
}
sessionManage
中取出当前在线用户的所有session
/**
* 刷新session
* 刷新在线用户角色
* @param save
*/
private void refreshSession(SysUser save) {
UserSessionManage userSessionManage = sessionManage.getUserSessionManage();
List<HttpSession> userSession = userSessionManage.getUserSession(save.getId());
userSession.forEach(session -> {
this.reloadUserAuthority(session);
});
}
当修改角色调用刷新session中的在线用户权限
/**
* 重新加载用户的权限
*
* @param session
*/
public void reloadUserAuthority(HttpSession session) {
try {
SecurityContext securityContext = (SecurityContext) session.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
Authentication authentication = securityContext.getAuthentication();
Object principal1 = authentication.getPrincipal();
if (principal1 instanceof SysUser) {
UserDetails principal = (SysUser) principal1;
/**
* 重载用户对象
*/
principal = this.loadUserByUsername(principal.getUsername());
// 重新new一个token,因为Authentication中的权限是不可变的.
UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(
principal, authentication.getCredentials(),
principal.getAuthorities());
result.setDetails(authentication.getDetails());
securityContext.setAuthentication(result);
}
} catch (Exception e) {
log.error("当前用户session有可能不存在");
}
}
本页面的代码本人测试无误,请放心参考,当然源码不提供公司的代码
,如果又不懂的地方请留言或者联系QQ:1810258114
及时帮你解答