Commit 9815f182 authored by cy's avatar cy

Merge remote-tracking branch 'origin/master'

parents 03a0d007 97402e78
...@@ -21,8 +21,8 @@ public class RedisConfig { ...@@ -21,8 +21,8 @@ public class RedisConfig {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer()); redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new StringRedisSerializer()); redisTemplate.setHashValueSerializer(new SerializeUtils());
redisTemplate.setValueSerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(new SerializeUtils());
redisTemplate.setConnectionFactory(factory); redisTemplate.setConnectionFactory(factory);
return redisTemplate; return redisTemplate;
} }
......
package cn.wisenergy.common.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import java.io.*;
/**
* @author: nh
* @date: 2021/04/08
* @description: redis的value序列化工具
*/
public class SerializeUtils implements RedisSerializer {
private static Logger logger = LoggerFactory.getLogger(SerializeUtils.class);
public static boolean isEmpty(byte[] data) {
return (data == null || data.length == 0);
}
/**
* 序列化
*
* @param object
* @return
* @throws SerializationException
*/
@Override
public byte[] serialize(Object object) throws SerializationException {
byte[] result = null;
if (object == null) {
return new byte[0];
}
try (
ByteArrayOutputStream byteStream = new ByteArrayOutputStream(128);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteStream)
) {
if (!(object instanceof Serializable)) {
throw new IllegalArgumentException(SerializeUtils.class.getSimpleName() + " requires a Serializable payload " +
"but received an object of type [" + object.getClass().getName() + "]");
}
objectOutputStream.writeObject(object);
objectOutputStream.flush();
result = byteStream.toByteArray();
} catch (Exception ex) {
logger.error("Failed to serialize", ex);
}
return result;
}
/**
* 反序列化
*
* @param bytes
* @return
* @throws SerializationException
*/
@Override
public Object deserialize(byte[] bytes) throws SerializationException {
Object result = null;
if (isEmpty(bytes)) {
return null;
}
try (
ByteArrayInputStream byteStream = new ByteArrayInputStream(bytes);
ObjectInputStream objectInputStream = new ObjectInputStream(byteStream)
) {
result = objectInputStream.readObject();
} catch (Exception e) {
logger.error("Failed to deserialize", e);
}
return result;
}
}
\ No newline at end of file
...@@ -63,6 +63,9 @@ public class UserLoginServiceImpl extends ServiceImpl<UsersMapper, User> impleme ...@@ -63,6 +63,9 @@ public class UserLoginServiceImpl extends ServiceImpl<UsersMapper, User> impleme
@Autowired @Autowired
private RedisService redisService; private RedisService redisService;
@Autowired
private KickoutSessionControlFilter kickoutSessionControlFilter;
//VIP客户初始密码 //VIP客户初始密码
private static final String PASSWORD = "123456"; private static final String PASSWORD = "123456";
...@@ -206,8 +209,7 @@ public class UserLoginServiceImpl extends ServiceImpl<UsersMapper, User> impleme ...@@ -206,8 +209,7 @@ public class UserLoginServiceImpl extends ServiceImpl<UsersMapper, User> impleme
UserToken userToken = new UserToken(userVo.getPhone(), credentialsSalt, USER_LOGIN_TYPE); UserToken userToken = new UserToken(userVo.getPhone(), credentialsSalt, USER_LOGIN_TYPE);
try { try {
subject.login(userToken); subject.login(userToken);
KickoutSessionControlFilter kitOut = new KickoutSessionControlFilter(); kickoutSessionControlFilter.changeSession(1);
kitOut.changeSession(1);
//3、构造返回参数 //3、构造返回参数
UserInfoVo userInfoVo = new UserInfoVo(); UserInfoVo userInfoVo = new UserInfoVo();
userInfoVo.setUserId(user.getId()); userInfoVo.setUserId(user.getId());
......
package cn.wisenergy.service.shir.filter; package cn.wisenergy.service.shir.filter;
import cn.wisenergy.common.utils.exception.Result;
import cn.wisenergy.model.app.AccountInfo; import cn.wisenergy.model.app.AccountInfo;
import cn.wisenergy.model.app.Staff; import cn.wisenergy.model.app.Staff;
import cn.wisenergy.model.app.User; import cn.wisenergy.model.app.User;
...@@ -8,16 +9,22 @@ import com.alibaba.fastjson.JSON; ...@@ -8,16 +9,22 @@ import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature; import com.alibaba.fastjson.serializer.SerializerFeature;
import com.itextpdf.text.log.Logger; import com.itextpdf.text.log.Logger;
import com.itextpdf.text.log.LoggerFactory; import com.itextpdf.text.log.LoggerFactory;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.shiro.SecurityUtils; import org.apache.shiro.SecurityUtils;
import org.apache.shiro.cache.Cache; import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.session.Session; import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.DefaultSessionKey; import org.apache.shiro.session.mgt.DefaultSessionKey;
import org.apache.shiro.subject.Subject; import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.AccessControlFilter; import org.apache.shiro.web.filter.AccessControlFilter;
import org.apache.shiro.cache.CacheManager; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import javax.servlet.ServletRequest; import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse; import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.Serializable; import java.io.Serializable;
...@@ -25,8 +32,9 @@ import java.util.Deque; ...@@ -25,8 +32,9 @@ import java.util.Deque;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.Map; import java.util.Map;
import java.util.concurrent.TimeUnit;
public class KickoutSessionControlFilter extends AccessControlFilter { public class KickoutSessionControlFilter extends AccessControlFilter{
private final Logger logger = LoggerFactory.getLogger(KickoutSessionControlFilter.class); private final Logger logger = LoggerFactory.getLogger(KickoutSessionControlFilter.class);
private boolean kickoutAfter = false; //踢出之前登录的/之后登录的用户 默认踢出之前登录的用户 private boolean kickoutAfter = false; //踢出之前登录的/之后登录的用户 默认踢出之前登录的用户
private int maxSession = 1; //同一个帐号最大会话数 默认1 private int maxSession = 1; //同一个帐号最大会话数 默认1
...@@ -34,6 +42,15 @@ public class KickoutSessionControlFilter extends AccessControlFilter { ...@@ -34,6 +42,15 @@ public class KickoutSessionControlFilter extends AccessControlFilter {
private MySessionManager sessionManager; private MySessionManager sessionManager;
private Cache<String, Deque<Serializable>> cache; private Cache<String, Deque<Serializable>> cache;
private static final long EXPIRE_TIME = 30 * 60;
private static final String DEFAULT_KICKOUT_CACHE_KEY_PREFIX = "shiro:cache:kickout:";
private String keyprefix = DEFAULT_KICKOUT_CACHE_KEY_PREFIX;
@Autowired
private RedisTemplate redisTemplate;
public void setKickoutAfter(boolean kickoutAfter) { public void setKickoutAfter(boolean kickoutAfter) {
this.kickoutAfter = kickoutAfter; this.kickoutAfter = kickoutAfter;
} }
...@@ -62,9 +79,8 @@ public class KickoutSessionControlFilter extends AccessControlFilter { ...@@ -62,9 +79,8 @@ public class KickoutSessionControlFilter extends AccessControlFilter {
@Override @Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
Subject subject = getSubject(request, response); Subject subject = getSubject(request, response);
Map<String, Object> map = new HashMap<>(); Map<String, Object> map = new HashMap<>();
//判断是否登录 // 没有登陆或没有设置“记住我”
if (!subject.isAuthenticated() && !subject.isRemembered()) { if (!subject.isAuthenticated() && !subject.isRemembered()) {
return true; return true;
} }
...@@ -75,71 +91,26 @@ public class KickoutSessionControlFilter extends AccessControlFilter { ...@@ -75,71 +91,26 @@ public class KickoutSessionControlFilter extends AccessControlFilter {
//5分钟 //5分钟
session.setTimeout(300000); session.setTimeout(300000);
Serializable sessionId = null; Serializable sessionId = session.getId();
String username = null; Integer userId = null;
// Deque<Serializable> deque = null;
try { try {
//客户端 //客户端
User user = (User) SecurityUtils.getSubject().getPrincipal(); User user = (User) SecurityUtils.getSubject().getPrincipal();
username = user.getPhone(); userId = user.getId();
sessionId = session.getId();
//读取缓存,没有就存入
//deque = cache.get(username);
} catch (Exception e) { } catch (Exception e) {
try { try {
//管理端 //管理端
sessionId = session.getId();
AccountInfo accountInfo = (AccountInfo) SecurityUtils.getSubject().getPrincipal(); AccountInfo accountInfo = (AccountInfo) SecurityUtils.getSubject().getPrincipal();
username = accountInfo.getUserName(); userId = accountInfo.getId();
//读取缓存,没有就存入
//deque = cache.get(username);
} catch (Exception en) { } catch (Exception en) {
//员工端 //员工端
Staff staff = (Staff) SecurityUtils.getSubject().getPrincipal(); Staff staff = (Staff) SecurityUtils.getSubject().getPrincipal();
username = staff.getLoginName(); userId = staff.getId();
sessionId = session.getId();
//读取缓存,没有就存入
//deque = cache.get(username);
}
}
/* //如果此用户没有session队列,也就是还没有登录过,缓存中没有,就new一个空队列,不然deque对象为空,会报空指针
if (deque == null) {
deque = new LinkedList<>();
} }
//如果队列里没有此sessionId,且用户没有被踢出;放入队列
if (!deque.contains(sessionId) && session.getAttribute("kickout") == null) {
//将sessionId存入队列
deque.push(sessionId);
//将用户的sessionId队列缓存
cache.put(username, deque);
} }
//如果队列里的sessionId数超出最大会话数,开始踢人
while (deque.size() > maxSession) {
Serializable kickoutSessionId;
if (kickoutAfter) { //如果踢出后者
kickoutSessionId = deque.removeFirst();
//踢出后再更新下缓存队列
} else { //否则踢出前者
kickoutSessionId = deque.removeLast();
//踢出后再更新下缓存队列
}
cache.put(username, deque);
try {
//获取被踢出的sessionId的session对象
DefaultSessionKey defaultSessionKey = new DefaultSessionKey(kickoutSessionId);
Session kickoutSession = sessionManager.getSession(defaultSessionKey);
//Session kickoutSession = (Session) sessionManager.getSession(String.valueOf(new DefaultSessionKey(kickoutSessionId)));
if (kickoutSession != null) {
//设置会话的kickout属性表示踢出了
kickoutSession.setAttribute("kickout", true);
}
} catch (Exception e) {
}
}*/
//如果被踢出了,直接退出,重定向到踢出后的地址 //如果被踢出了,直接退出,重定向到踢出后的地址
if (session.getAttribute("kickout") != null) { if (session.getAttribute("kickout") != null) {
logger.info("------" + "踢出用户" + username + "登录sessionId=" + sessionId + "------"); logger.info("------" + "踢出用户" + userId + "登录sessionId=" + sessionId + "------");
//会话被踢出了 //会话被踢出了
try { try {
//退出登录 //退出登录
...@@ -174,49 +145,35 @@ public class KickoutSessionControlFilter extends AccessControlFilter { ...@@ -174,49 +145,35 @@ public class KickoutSessionControlFilter extends AccessControlFilter {
Subject subject = SecurityUtils.getSubject(); Subject subject = SecurityUtils.getSubject();
Session session = subject.getSession(); Session session = subject.getSession();
session.setTimeout(300000); session.setTimeout(300000);
Serializable sessionId = session.getId(); Serializable sessionId = session.getId();
String username = null; Integer userId = null;
Deque<Serializable> deque = null;
if(type == 1){ if(type == 1){
User user=(User)subject.getPrincipal(); User user=(User)subject.getPrincipal();
username=user.getPhone(); userId=user.getId();
}else if(type == 2){ }else if(type == 2){
AccountInfo account=(AccountInfo)subject.getPrincipal(); AccountInfo account=(AccountInfo)subject.getPrincipal();
username=account.getUserName(); userId=account.getId();
}else{ }else{
Staff staff=(Staff)subject.getPrincipal(); Staff staff=(Staff)subject.getPrincipal();
username=staff.getLoginName(); userId=staff.getId();
} }
//读取缓存,没有就存入 //读取缓存,没有就存入
deque = cache.get(username); Deque<Serializable> deque =(Deque<Serializable>) redisTemplate.opsForValue().get(getRedisKickoutKey(userId));
//如果此用户没有session队列,也就是还没有登录过,缓存中没有,就new一个空队列,不然deque对象为空,会报空指针 //如果此用户没有session队列,也就是还没有登录过,缓存中没有,就new一个空队列,不然deque对象为空,会报空指针
if (deque == null) { if (deque == null || deque.size()==0) {
deque = new LinkedList<>(); deque = new LinkedList<>();
} }
//如果队列里没有此sessionId,且用户没有被踢出;放入队列 //如果队列里没有此sessionId,且用户没有被踢出;放入队列
if (!deque.contains(sessionId) && session.getAttribute("kickout") == null) { if (!deque.contains(sessionId) && session.getAttribute("kickout") == null) {
//将sessionId存入队列 //将sessionId存入队列
deque.push(sessionId); deque.push(sessionId);
//将用户的sessionId队列缓存
cache.put(username, deque);
} }
//如果队列里的sessionId数超出最大会话数,开始踢人 //如果队列里的sessionId数超出最大会话数,开始踢人
while (deque.size() > maxSession) { while (deque.size() > maxSession) {
Serializable kickoutSessionId; Serializable kickoutSessionId = kickoutAfter?deque.removeFirst():deque.removeLast();
if (kickoutAfter) { //如果踢出后者
kickoutSessionId = deque.removeFirst();
//踢出后再更新下缓存队列
} else { //否则踢出前者
kickoutSessionId = deque.removeLast();
//踢出后再更新下缓存队列
}
cache.put(username, deque);
try { try {
//获取被踢出的sessionId的session对象 //获取被踢出的sessionId的session对象
DefaultSessionKey defaultSessionKey = new DefaultSessionKey(kickoutSessionId); Session kickoutSession = sessionManager.getSession(new DefaultSessionKey(kickoutSessionId));
Session kickoutSession = sessionManager.getSession(defaultSessionKey);
//Session kickoutSession = (Session) sessionManager.getSession(String.valueOf(new DefaultSessionKey(kickoutSessionId)));
if (kickoutSession != null) { if (kickoutSession != null) {
//设置会话的kickout属性表示踢出了 //设置会话的kickout属性表示踢出了
kickoutSession.setAttribute("kickout", true); kickoutSession.setAttribute("kickout", true);
...@@ -224,6 +181,34 @@ public class KickoutSessionControlFilter extends AccessControlFilter { ...@@ -224,6 +181,34 @@ public class KickoutSessionControlFilter extends AccessControlFilter {
} catch (Exception e) { } catch (Exception e) {
} }
} }
// 更新redis中的用户登录队列
redisTemplate.opsForValue().set(getRedisKickoutKey(userId), deque, EXPIRE_TIME, TimeUnit.SECONDS);
}
String getRedisKickoutKey(Integer userId) {
return keyprefix + userId;
}
// 抛出未登录异常
private void thrLogoutException(HttpServletResponse response){
PrintWriter writer = null;
try {
Result result = new Result();
result.setResult(Result.RESULT_FLG.FAIL.getValue());
// result.setErrorCode();
// result.setErrorMsg();
response.setContentType("application/json; charset=UTF-8");
writer = response.getWriter();
writer.write(JSON.toJSONString(result));
writer.flush();
} catch (Exception e) {
IOUtils.closeQuietly(writer);
logger.error("接口异常:{}"+ExceptionUtils.getFullStackTrace(e));
} finally {
if (writer != null) {
writer.close();
}
}
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment