僅僅思路,這是springsecurety的
package com.dbapp.fly.config.security;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.dbapp.fly.entity.SysUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
//登入使用者認證通過後,顯示登入成功頁面前,做的操作。
@Component
public class MyAuthenctiationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
private static final Logger logger = LoggerFactory.getLogger(MyAuthenctiationSuccessHandler.class);
// key為sessionId,value為HttpSession,使用static,定義靜态變量,使之程式運作時,一直存在記憶體中。
// 儲存所有已經登入使用者的會話(每個浏覽器一個會話)
public static HashMap<String, HttpSession> sessionMap = new HashMap<String, HttpSession>();
@Autowired
// @Qualifier("sessionRegistry")
private SessionRegistry sessionRegistry;
// @Bean(name="sessionRegistry",value="sessionRegistry")
@Bean
// @Bean(name="sessionRegistry")
public SessionRegistry getSessionRegistry() {
return new SessionRegistryImpl();
}
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws ServletException, IOException {
// 1.登入認證成功後,擷取使用者名
//(隻能在認證成功通過後,才能獲得sc,不然在CustomUserService implements UserDetailsService的loadUserByUsername方法中是第二次才能擷取到)
SecurityContext sc = SecurityContextHolder.getContext();
String currentuser = ((SysUser) sc.getAuthentication().getPrincipal()).getUserName();
logger.info("目前登入使用者:" + currentuser);
// 2.先判斷使用者是否重複登入
Iterator<Entry<String, HttpSession>> iterator = sessionMap.entrySet().iterator();
while(iterator.hasNext()) {
Map.Entry<String, HttpSession> entry = iterator.next();
HttpSession session = entry.getValue();
// 2.1 判斷session中所包含的使用者名稱是否有目前登入使用者
String username = SessionUtil.getUserName(session);
if (currentuser.equals(username)) {
logger.info("使用者:" + currentuser + "已經在其它地方登入過,将踢除!");
SessionUtil.expireSession(session);
logger.info("删除的會話:"+entry.getKey());
// 2.2 從sessionMap中踢除會話
iterator.remove();
// 2.3 從sessionRegistry中踢除會話
sessionRegistry.removeSessionInformation(session.getId());
}
}
/*//以下這種方法會引起java.util.ConcurrentModificationException: null 錯誤, HashMap
// 2.先判斷使用者是否重複登入
for (Entry<String, HttpSession> entry : sessionMap.entrySet()) {
HttpSession session = entry.getValue();
// 2.1 判斷session中所包含的使用者名稱是否有目前登入使用者
String username = SessionUtil.getUserName(session);
if (currentuser.equals(username)) {
logger.info("使用者:" + currentuser + "已經在其它地方登入過,将踢除!");
SessionUtil.expireSession(session);
logger.info(entry.getKey());
sessionMap.remove(entry.getKey());//這裡會引起同步錯誤
sessionRegistry.removeSessionInformation(session.getId());
}
}*/
// 3.将目前session儲存到sessionMap中
logger.info("将目前會話:" + request.getSession().getId() + ",儲存到sessionMap");
sessionMap.put(request.getSession().getId(), request.getSession());
for (Entry<String, HttpSession> entry : sessionMap.entrySet()) {
logger.info("顯示已經儲存的sessionMap:Key: " + entry.getKey() + " Value: " + entry.getValue());
}
// 4.列印所有認證通過的使用者(包含重複登入的,不過上面已經踢除了)
List<Object> principals = sessionRegistry.getAllPrincipals();
List<String> usersNamesList = new ArrayList<String>();
for (Object principal: principals) {
if (principal instanceof SysUser) {
usersNamesList.add(((SysUser) principal).getUserName());
}
}
logger.info("已經認證通過的使用者數:"+usersNamesList.size()+", 已經認證通過使用者:"+usersNamesList.toString());
// response.sendRedirect("/");
super.onAuthenticationSuccess(request, response, authentication);
}
}
package com.dbapp.fly.config.security;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//啟動類加上注解@ServletComponentScan,這樣才能掃描到監聽器
//@WebListener
public class MySessionListner implements HttpSessionListener {
private static final Logger logger = LoggerFactory.getLogger(MySessionListner.class);
/**
* 建立session時(打開浏覽器通路登入頁面時,伺服器會建立一個新的session)
*/
@Override
public void sessionCreated(HttpSessionEvent httpSessionEvent) {
System.out.println("建立session");
}
/**
* 删除session時(退出系統)
*/
@Override
public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
logger.info("銷毀session時");
MyAuthenctiationSuccessHandler.sessionMap.remove(httpSessionEvent.getSession().getId());
}
}
package com.dbapp.fly.config.security;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MywebConfig implements WebMvcConfigurer {
@Bean
public ServletListenerRegistrationBean listenerRegist() {
ServletListenerRegistrationBean srb = new ServletListenerRegistrationBean();
srb.setListener(new MySessionListner());
System.out.println("listener");
return srb;
}
}
package com.dbapp.fly.config.security;
import java.util.Enumeration;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import com.dbapp.fly.entity.SysUser;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.session.SessionInformation;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.userdetails.User;
public class SessionUtil {
private static SecurityContext attribute;
/**
* 根據目前session擷取目前登入使用者對象
* @param session
* @return guser
*/
public static SysUser getUser(HttpSession session) {
try {
attribute = (SecurityContext) session.getAttribute("SPRING_SECURITY_CONTEXT");
SysUser principal = (SysUser) attribute.getAuthentication().getPrincipal();
return principal;
} catch (Exception e) {
}
return null;
}
/**
* 根據目前session擷取目前登入使用者ID
* @param session
* @return guser
*/
public static Long getUserId(HttpSession session) {
try {
attribute = (SecurityContext) session.getAttribute("SPRING_SECURITY_CONTEXT");
SysUser principal = (SysUser) attribute.getAuthentication().getPrincipal();
return principal.getId();
} catch (Exception e) {
}
return null;
}
/**
* 根據session擷取使用者名稱
* @param session
* @return void
*/
public static String getUserName(HttpSession session) {
try {
attribute = (SecurityContext) session.getAttribute("SPRING_SECURITY_CONTEXT");
SysUser principal = (SysUser) attribute.getAuthentication().getPrincipal();
return principal.getUserName();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 根據session擷取count
* session中包含一個count鍵預設為null,可以用來統計登入次數
* @param session
* @return void
*/
public static void count(HttpSession session) {
ServletContext context = session.getServletContext();
System.out.println("sessionid:"+session.getId()+",的count是:"+context.getAttribute("count"));
}
/**
* 辨識使用者是否已經登入,如果已經登入就不能登入了。
*
* @param request
* @param sessionRegistry
* @param loginedUser
*/
public static void deleteSameUser(HttpServletRequest request, SessionRegistry sessionRegistry, User loginedUser) {
SecurityContext sc = (SecurityContext) request.getSession().getAttribute("SPRING_SECURITY_CONTEXT");
List<SessionInformation> sessionsInfo;
sessionsInfo = sessionRegistry.getAllSessions(sc.getAuthentication().getPrincipal(), true);
String currentSessionId;
if (null != sessionsInfo && sessionsInfo.size() == 0) {
sessionRegistry.registerNewSession(request.getSession().getId(), sc.getAuthentication().getPrincipal());
sessionsInfo = sessionRegistry.getAllSessions(sc.getAuthentication().getPrincipal(), false);
}
currentSessionId = sessionsInfo.get(0).getSessionId();
List<Object> o = sessionRegistry.getAllPrincipals();
for (Object principal : o) {
if (principal instanceof User && (loginedUser.getUsername().equals(((User) principal).getUsername()))) {
List<SessionInformation> oldSessionsInfo = sessionRegistry.getAllSessions(principal, false);
if (null != oldSessionsInfo && oldSessionsInfo.size() > 0 && !oldSessionsInfo.get(0).getSessionId().equals(currentSessionId)) {
for (SessionInformation sessionInformation : sessionsInfo) {
//目前session失效
sessionInformation.expireNow();
sc.setAuthentication(null);
sessionRegistry.removeSessionInformation(currentSessionId);
//throw new GeneralServerExistException(ErrorMessage.ALONG_LOGIN_ERROTR.toString());
}
}
}
}
}
/**
* 會話銷毀(剔除前一個使用者)
*
* @param , SysMessageService sysMessageService
*/
public static void expireSession(HttpSession session) {
session.invalidate();
}
/**
* 剔除前一個使用者
*
* @param request
* @param sessionRegistry
* @param loginedUser
* @param , SysMessageService sysMessageService
*/
public static void dropPreviousUser2(HttpServletRequest request, SessionRegistry sessionRegistry, SysUser loginedUser) {
List<SessionInformation> sessionsInfo = null;
//登入以後session裡才會加入鍵名為"SPRING_SECURITY_CONTEXT"的字段
SecurityContext sc = (SecurityContext) request.getSession().getAttribute("SPRING_SECURITY_CONTEXT");
if(sc!=null) {
System.out.println("!!!!!!!!!!!!"+sc.getAuthentication().getPrincipal().toString());
//擷取目前登入使用者的會話資訊集合
sessionsInfo = sessionRegistry.getAllSessions(sc.getAuthentication().getPrincipal(), false);
if (sessionsInfo.size() > 0) {
//目前會話ID
String currentSessionId = sessionsInfo.get(0).getSessionId();
//擷取所有已經登入的使用者
List<Object> o = sessionRegistry.getAllPrincipals();
for (Object principal : o) {
//當登入使用者的名字和已經登入使用者的名字相同,也就是登入使用者已經登入過了。
if (principal instanceof User && (loginedUser.getUserName().equals(((User) principal).getUsername()))) {
//擷取已經登入使用者的會話資訊集合
List<SessionInformation> oldSessionsInfo = sessionRegistry.getAllSessions(principal, false);
//如果會話資訊不為空且會話資訊的ID不等于目前會話ID
if (null != oldSessionsInfo && oldSessionsInfo.size() > 0 && !oldSessionsInfo.get(0).getSessionId().equals(currentSessionId)) {
//周遊已經登入使用者的會話資訊,并設定過期,即删除session
for (SessionInformation sessionInformation : oldSessionsInfo) {
//舊使用者的session失效
//send message
//sysMessageService.sendMessage(((User) principal).getUsername(), new SysMessage(null, Consts.NOTIFICATION_TYPE_HADLOGIN_CONTENT, 5, Consts.NOTIFICATION_ACCEPT_TYPE_HADLOGIN));
sessionInformation.expireNow();
}
}
}
}
}
}
}
/**
* session 失效
*
* @param request
* @param sessionRegistry
*/
public static void expireSession(HttpServletRequest request, User user, SessionRegistry sessionRegistry) {
List<SessionInformation> sessionsInfo = null;
if (null != user) {
List<Object> o = sessionRegistry.getAllPrincipals();
for (Object principal : o) {
if (principal instanceof User && (user.getUsername().equals(((User) principal).getUsername()))) {
sessionsInfo = sessionRegistry.getAllSessions(principal, false);
}
}
} else if (null != request) {
SecurityContext sc = (SecurityContext) request.getSession().getAttribute("SPRING_SECURITY_CONTEXT");
if (null != sc.getAuthentication().getPrincipal()) {
sessionsInfo = sessionRegistry.getAllSessions(sc.getAuthentication().getPrincipal(), false);
sc.setAuthentication(null);
}
}
if (null != sessionsInfo && sessionsInfo.size() > 0) {
for (SessionInformation sessionInformation : sessionsInfo) {
//目前session失效
sessionInformation.expireNow();
sessionRegistry.removeSessionInformation(sessionInformation.getSessionId());
}
}
}
public void showsession(HttpServletRequest request) {
//擷取session
HttpSession session = request.getSession();
// 擷取session中所有的鍵值
Enumeration<String> attrs = session.getAttributeNames();
// 周遊attrs中的
while(attrs.hasMoreElements()){
// 擷取session鍵值
String name = attrs.nextElement().toString();
// 根據鍵值取session中的值
Object vakue = session.getAttribute(name);
// 列印結果
System.out.println("--sessionID"+session.getId());
System.out.println("--名字:" + name +"-----\n");
System.out.println("--值:" + vakue +"--------\n");
}
}
}