Commit 781cd5ae by 陈健智

单账号登录限制

parent 1f8c813c
...@@ -11,6 +11,7 @@ import com.zhiwei.brandkbs2.service.UserService; ...@@ -11,6 +11,7 @@ import com.zhiwei.brandkbs2.service.UserService;
import com.zhiwei.brandkbs2.util.RedisUtil; import com.zhiwei.brandkbs2.util.RedisUtil;
import com.zhiwei.brandkbs2.util.Tools; import com.zhiwei.brandkbs2.util.Tools;
import com.zhiwei.middleware.auth.util.JwtUtil; import com.zhiwei.middleware.auth.util.JwtUtil;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.ProceedingJoinPoint;
...@@ -92,9 +93,13 @@ public class AuthAspect { ...@@ -92,9 +93,13 @@ public class AuthAspect {
} else { } else {
String uid = tokenInfo.get(GenericAttribute.USER_ID).toString(); String uid = tokenInfo.get(GenericAttribute.USER_ID).toString();
// session单账号登录限制校验 // session单账号登录限制校验
// if (!checkSession(request, uid)){ Pair<Boolean, String> pair = checkSession(request, uid);
// return joinPoint.proceed(); if (!pair.getLeft()){
// } if (null != pair.getRight()) {
UserThreadLocal.set(new UserInfo().setIsOtherLogin(true).setIpAddress(pair.getRight()));
}
return joinPoint.proceed();
}
UserInfo userInfo = UserService.queryUserInfo(uid, request.getHeader("pid")); UserInfo userInfo = UserService.queryUserInfo(uid, request.getHeader("pid"));
if (null == userInfo) { if (null == userInfo) {
userInfo = new UserInfo().setUserId(uid).setProjectId(request.getHeader("pid")); userInfo = new UserInfo().setUserId(uid).setProjectId(request.getHeader("pid"));
...@@ -113,19 +118,27 @@ public class AuthAspect { ...@@ -113,19 +118,27 @@ public class AuthAspect {
return joinPoint.proceed(); return joinPoint.proceed();
} }
private Boolean checkSession(HttpServletRequest request, String uid) { /**
* 比对登录时的sessionId与缓存中(当前登录中)的sessionId 限制单账号登录
* @param request
* @param uid
* @return
*/
private Pair<Boolean, String> checkSession(HttpServletRequest request, String uid) {
// 小程序端不限制 // 小程序端不限制
if (request.getRequestURI().contains("/brandkbs/mobile/")){ if (request.getRequestURI().contains("/brandkbs/mobile/")){
return true; return Pair.of(true, null);
} }
HttpSession session = request.getSession(); HttpSession session = request.getSession();
String sessionId = session.getId(); String sessionId = session.getId();
String cacheSessionId = redisUtil.get(RedisKeyPrefix.userSessionKey(uid)); // 缓存中为当前登录中的用户sessionId、ip地址
if (null == cacheSessionId) { String sessionIdAndIp = redisUtil.get(RedisKeyPrefix.userSessionKey(uid));
redisUtil.setExpire(RedisKeyPrefix.userSessionKey(uid), sessionId, 7, TimeUnit.DAYS); if (null == sessionIdAndIp){
return Pair.of(false, null);
} }
String[] split = sessionIdAndIp.split("_");
// 已登录状态 // 已登录状态
return null == cacheSessionId || Objects.equals(sessionId, cacheSessionId); return Pair.of(Objects.equals(sessionId, split[0]), split[1]);
} }
// @Around("auth()") // @Around("auth()")
......
...@@ -48,9 +48,15 @@ public class UserThreadLocal { ...@@ -48,9 +48,15 @@ public class UserThreadLocal {
} }
private static void checkExist() { private static void checkExist() {
// 登录信息过期
if (null == TOKEN_USER_INFO.get()) { if (null == TOKEN_USER_INFO.get()) {
ExceptionCast.cast(LoginCodeEnum.LOGIN_EXPIRED_ERROR); ExceptionCast.cast(LoginCodeEnum.LOGIN_EXPIRED_ERROR);
} }
// 异地登录
if (null != TOKEN_USER_INFO.get().getIsOtherLogin() && TOKEN_USER_INFO.get().getIsOtherLogin()){
String message = String.format("您的账号已在别处登陆(登陆地址:%s),您已被强制下线!如果这不是您本人操作,请立即检查账号安全。", TOKEN_USER_INFO.get().getIpAddress());
LoginCodeEnum.LOGIN_OTHER_ERROR.setMessage(message);
ExceptionCast.cast(LoginCodeEnum.LOGIN_OTHER_ERROR);
}
} }
} }
...@@ -49,7 +49,11 @@ public enum LoginCodeEnum implements ResultCode { ...@@ -49,7 +49,11 @@ public enum LoginCodeEnum implements ResultCode {
/** /**
* 登录信息过期 * 登录信息过期
*/ */
LOGIN_EXPIRED_ERROR(false, 1010, "登录信息过期,请重新登陆", 200); LOGIN_EXPIRED_ERROR(false, 1010, "登录信息过期,请重新登陆", 200),
/**
* 异地登陆
*/
LOGIN_OTHER_ERROR(false, 1011, "您的账号已在别处登陆(登陆地址:%s),您已被强制下线!如果这不是您本人操作,请立即检查账号安全。", 200);
/** /**
* 操作是否成功 * 操作是否成功
...@@ -62,7 +66,7 @@ public enum LoginCodeEnum implements ResultCode { ...@@ -62,7 +66,7 @@ public enum LoginCodeEnum implements ResultCode {
/** /**
* 提示信息 * 提示信息
*/ */
final String message; String message;
/** /**
* 聚合状态码 * 聚合状态码
*/ */
...@@ -94,4 +98,8 @@ public enum LoginCodeEnum implements ResultCode { ...@@ -94,4 +98,8 @@ public enum LoginCodeEnum implements ResultCode {
public int aggCode() { public int aggCode() {
return aggCode; return aggCode;
} }
public void setMessage(String message){
this.message = message;
}
} }
...@@ -24,6 +24,20 @@ public class UserInfo { ...@@ -24,6 +24,20 @@ public class UserInfo {
private Long expiredTime; private Long expiredTime;
private long phoneNumber; private long phoneNumber;
private Boolean isOtherLogin;
private String ipAddress;
public UserInfo setIsOtherLogin(Boolean isOtherLogin) {
this.isOtherLogin = isOtherLogin;
return this;
}
public UserInfo setIpAddress(String ipAddress) {
this.ipAddress = ipAddress;
return this;
}
public UserInfo setUserId(String userId) { public UserInfo setUserId(String userId) {
this.userId = userId; this.userId = userId;
return this; return this;
......
...@@ -9,6 +9,7 @@ import com.zhiwei.brandkbs2.common.RedisKeyPrefix; ...@@ -9,6 +9,7 @@ import com.zhiwei.brandkbs2.common.RedisKeyPrefix;
import com.zhiwei.brandkbs2.config.Constant; import com.zhiwei.brandkbs2.config.Constant;
import com.zhiwei.brandkbs2.dao.ProjectDao; import com.zhiwei.brandkbs2.dao.ProjectDao;
import com.zhiwei.brandkbs2.dao.UserDao; import com.zhiwei.brandkbs2.dao.UserDao;
import com.zhiwei.brandkbs2.dao.UserLogRecordDao;
import com.zhiwei.brandkbs2.dao.impl.UserOldDaoImpl; import com.zhiwei.brandkbs2.dao.impl.UserOldDaoImpl;
import com.zhiwei.brandkbs2.dao.impl.UserProjectOldDaoImpl; import com.zhiwei.brandkbs2.dao.impl.UserProjectOldDaoImpl;
import com.zhiwei.brandkbs2.enmus.RoleEnum; import com.zhiwei.brandkbs2.enmus.RoleEnum;
...@@ -16,10 +17,7 @@ import com.zhiwei.brandkbs2.enmus.response.LoginCodeEnum; ...@@ -16,10 +17,7 @@ import com.zhiwei.brandkbs2.enmus.response.LoginCodeEnum;
import com.zhiwei.brandkbs2.exception.ExceptionCast; import com.zhiwei.brandkbs2.exception.ExceptionCast;
import com.zhiwei.brandkbs2.model.CommonCodeEnum; import com.zhiwei.brandkbs2.model.CommonCodeEnum;
import com.zhiwei.brandkbs2.model.ResponseResult; import com.zhiwei.brandkbs2.model.ResponseResult;
import com.zhiwei.brandkbs2.pojo.Project; import com.zhiwei.brandkbs2.pojo.*;
import com.zhiwei.brandkbs2.pojo.User;
import com.zhiwei.brandkbs2.pojo.UserInfo;
import com.zhiwei.brandkbs2.pojo.UserRole;
import com.zhiwei.brandkbs2.pojo.dto.UserDTO; import com.zhiwei.brandkbs2.pojo.dto.UserDTO;
import com.zhiwei.brandkbs2.pojo.vo.MobileLoginVO; import com.zhiwei.brandkbs2.pojo.vo.MobileLoginVO;
import com.zhiwei.brandkbs2.pojo.vo.PageVO; import com.zhiwei.brandkbs2.pojo.vo.PageVO;
...@@ -86,6 +84,9 @@ public class UserServiceImpl implements UserService { ...@@ -86,6 +84,9 @@ public class UserServiceImpl implements UserService {
@Resource(name = "userCenterServiceImpl") @Resource(name = "userCenterServiceImpl")
private UserCenterService userCenterService; private UserCenterService userCenterService;
@Resource(name = "UserLogRecordDao")
private UserLogRecordDao userLogRecordDao;
@Value("${wx.accesstoken.url}") @Value("${wx.accesstoken.url}")
private String wechatAccessTokenUrl; private String wechatAccessTokenUrl;
...@@ -381,8 +382,8 @@ public class UserServiceImpl implements UserService { ...@@ -381,8 +382,8 @@ public class UserServiceImpl implements UserService {
@Override @Override
public boolean checkUserRoles() { public boolean checkUserRoles() {
// String uid = saveLoginUserSession(); String uid = saveLoginUserSession();
User user = userDao.findOneById(UserThreadLocal.getUserId()); User user = userDao.findOneById(uid);
if (null == user) { if (null == user) {
return false; return false;
} }
...@@ -398,7 +399,29 @@ public class UserServiceImpl implements UserService { ...@@ -398,7 +399,29 @@ public class UserServiceImpl implements UserService {
HttpServletRequest request = Objects.requireNonNull(servletRequestAttributes).getRequest(); HttpServletRequest request = Objects.requireNonNull(servletRequestAttributes).getRequest();
Map<String, Object> map = JwtUtil.unsign(request.getHeader(jwtKey), Map.class); Map<String, Object> map = JwtUtil.unsign(request.getHeader(jwtKey), Map.class);
String userId = map.get(GenericAttribute.USER_ID).toString(); String userId = map.get(GenericAttribute.USER_ID).toString();
redisUtil.setExpire(RedisKeyPrefix.userSessionKey(userId), request.getSession().getId(), 7, TimeUnit.DAYS); String ipAddress = Tools.getIpAddress(request);
String sessionId = request.getSession().getId();
String str = sessionId + "_" + ipAddress;
// 当前缓存中的sessionIdAndIp
String sessionIdAndIp = redisUtil.get(RedisKeyPrefix.userSessionKey(userId));
// 记录异地登录
if (Objects.nonNull(sessionIdAndIp)){
String[] split = sessionIdAndIp.split("_");
// 比较ip地址sessionId 若不相等则记录为异地登录
if (!Objects.equals(sessionId, split[0]) && !Objects.equals(ipAddress, split[1])){
long now = System.currentTimeMillis();
String projectId = request.getHeader("pid");
UserInfo userInfo;
if (null != (userInfo = queryUserInfo(userId, projectId))) {
String description = "异地登录:" + split[1] + "->" + ipAddress;
userLogRecordDao.insertOne(new UserLogRecord(projectId, userId, userInfo.getNickname(), description, userInfo.getRoleId(), now, now, null),
userLogRecordDao.generateCollectionName());
}else {
log.error("异地登录操作记录-用户信息解析异常,projectId:{},userId:{},ip:{}->{}", projectId, userId, sessionIdAndIp, str);
}
}
}
redisUtil.setExpire(RedisKeyPrefix.userSessionKey(userId), str, 7, TimeUnit.DAYS);
return userId; return userId;
} }
......
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