業務背景: 管理員更改其他用戶權限,正好用戶在登陸狀態下,無法刷新管理員剛賦值的權限,只能退出登錄,重新登錄才能擁有新權限.
業務需求:管理員更改權限,其他用戶不退出登錄,可以擁有新權限,動態刷新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
及時幫你解答