您的位置:首页 > 其它

站点单用户登录,后面登录上来的会把前面登录的人踢下线

2018-03-01 17:41 197 查看
公司平台接受监管后,系统整改,其中一个就是一个用户账号只能在一个地方登录,别的地方登录上来后,当前登录的人必须下线。

因为一直做web开发,之前给某公司做过这个功能,只不过那个是8年前,比较老的方式,单体系统,目前都是分布式。但是其实实现原理都是一样的。分布式系统只是部署了多份app。那么就得依赖一个第三方存储的地方,可以是db,可以是缓存。这里我就用缓存redis。

首先说一下这个单账号只能一个ip登录的原理:

明天继续。先贴代码:

LoginAloneHttpSessionListener.java

import javax.servlet.ServletContext;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.support.WebApplicationContextUtils;

@Component
@WebListener
public class LoginAloneHttpSessionListener implements HttpSessionListener,  HttpSessionAttributeListener {

private static Logger logger = Logger.getLogger(LoginAloneHttpSessionListener.class);

@Autowired
private StringRedisTemplate stringRedisTemplate;

/**初始化方法 stringRedisTemplate
*
* @param session
* @author chenweixian 陈惟鲜
* @date 2018年2月26日 上午10:40:02
*/
public void initStringRedisTemplate(HttpSession session){
if (stringRedisTemplate == null){
ServletContext servletContext = session.getServletContext();
ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext);
stringRedisTemplate = context.getBean("stringRedisTemplate", StringRedisTemplate.class);
}
}

@Override
public void sessionCreated(HttpSessionEvent event) {
this.initStringRedisTemplate(event.getSession());

//        logger.info("============session【"+event.getSession().getId()+"】 已创建");
}

@Override
public void sessionDestroyed(HttpSessionEvent event) {
this.initStringRedisTemplate(event.getSession());
BoundHashOperations<String, String, String> boundHashOperations = stringRedisTemplate.boundHashOps(RedisContants.ADMIN_LOGIN_MAP);
boundHashOperations.delete(event.getSession().getId());

//        logger.info("============session【"+event.getSession().getId()+"】 已销毁");
}

@Override
public void attributeAdded(HttpSessionBindingEvent event) {

this.handleUserInfo(event);

//        logger.info("============session【"+event.getSession().getId()+"】====attribute  Added");

}

@Override
public void attributeRemoved(HttpSessionBindingEvent event) {
if (SystemContants.USER_INFO.equals(event.getName())){
this.initStringRedisTemplate(event.getSession());
BoundHashOperations<String, String, String> boundHashOperations = stringRedisTemplate.boundHashOps(RedisContants.ADMIN_LOGIN_MAP);
boundHashOperations.delete(event.getSession().getId());
}

//        logger.info("============session【"+event.getSession().getId()+"】====attribute Removed");
}

@Override
public void attributeReplaced(HttpSessionBindingEvent event) {
this.handleUserInfo(event);

//        logger.info("============session【"+event.getSession().getId()+"】=====attribute Replaced");

}

/**处理用户信息
*
* @param event
* @author chenweixian 陈惟鲜
* @date 2018年2月26日 上午11:07:11
*/
private void handleUserInfo(HttpSessionBindingEvent event){
if (SystemContants.USER_INFO.equals(event.getName())){
this.initStringRedisTemplate(event.getSession());
UserVo userVo = (UserVo)event.getValue();
BoundHashOperations<String, String, String> boundHashOperations = stringRedisTemplate.boundHashOps(RedisContants.ADMIN_LOGIN_MAP);
// 踢出之前在线的用户
if (userVo != null){
if (boundHashOperations.keys().size() > 0){
for (String key :  boundHashOperations.keys()){
if(userVo.getUserId().equalsIgnoreCase(boundHashOperations.get(key))){
// 踢出
boundHashOperations.delete(key);
}
}
}
}

// 加入当前登录用户
boundHashOperations.put(event.getSession().getId(), userVo.getUserId());
}
}

}


LoginFilter.java

import java.io.IOException;
import java.util.regex.Pattern;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.context.support.WebApplicationContextUtils;
import com.opensymphony.oscache.util.StringUtil;

/**登录过滤器
*
* @author : chewneixian 陈惟鲜
* @create_date 2016年8月3日 上午11:35:23
*
*/
@Service
@WebFilter(filterName="loginFilter", urlPatterns={
"*.do",
})
public class LoginFilter implements Filter {
@Autowired
private DictionaryVoService dictionaryVoService;
// 忽略的URL
//    String PASS_VALIDATION_URL = ConfigPropertiesUtil.getProp("login.ignore.passUrl");

//     日志对象
private static Logger logger = Logger.getLogger(LoginFilter.class);
@Autowired
private StringRedisTemplate stringRedisTemplate;

public void init(FilterConfig filterConfig) throws ServletException {
ServletContext servletContext = filterConfig.getServletContext();
ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext);
if (stringRedisTemplate == null){
stringRedisTemplate = context.getBean("stringRedisTemplate", StringRedisTemplate.class);
}
if (dictionaryVoService == null){
dictionaryVoService = context.getBean("dictionaryVoService", DictionaryVoService.class);
}
}

public void destroy() {
}

public void doFilter(ServletRequest req, ServletResponse res,FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String PASS_VALIDATION_URL = dictionaryVoService.findFieldValue(DictionaryContants.TYPE_ID_PLATFORM_INFO, StatusContants.LOGIN_IGNORE_PASSURL.getIndex());

// 是否跳过检查
String requestUri = request.getRequestURI();
requestUri = requestUri.replace(request.getContextPath()+"/", ""); // 去掉工程名/
if (Pattern.matches(PASS_VALIDATION_URL,requestUri)) {
chain.doFilter(req, res);
return ;
}
// 获取登录用户信息
UserVo userVo = (UserVo)request.getSession().getAttribute(SystemContants.USER_INFO);
if (userVo == null){
// 用户未登录
logger.error("您未登录,或登录超时,或您的账号在其他地方登录");
response.sendRedirect(request.getContextPath() + "/login_to.do");
return ;
}
if (!this.isLogined(request.getSession().getId(), userVo.getUserId())){
// 用户未登录
logger.error("您的账号已经在异地登录,请重新登录修改密码。");
response.sendRedirect(request.getContextPath() + "/login_error.do");
return ;
}

chain.doFilter(req, res);
}

/**
* isLogining-用于判断用户是否已经登录
* @param        sessionUserName String-登录的用户名
* @return boolean-该用户是否已经登录的标志
* */
public boolean isLogined(String nowSessionId, String nowUserId){
boolean result = false;
BoundHashOperations<String, String, String> boundHashOperations = stringRedisTemplate.boundHashOps(RedisContants.ADMIN_LOGIN_MAP);
if (boundHashOperations.keys().size() > 0){
// 当前登线程用户ID, 在集合中没有记录
String sessionUserId = boundHashOperations.get(nowSessionId);
if (!StringUtil.isEmpty(sessionUserId)){
// 当前使用这个用户ID的线程ID
String mySessionId = "";
for (String key :  boundHashOperations.keys()){
if(nowUserId.equalsIgnoreCase(boundHashOperations.get(key))){
mySessionId = key;
break;
}
}
// 当前线程与登录用户线程ID相等,则登录
if (nowSessionId.equals(mySessionId)){
result = true;
}
}
}
return result;
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐