限制统一账号不同终端登录

master
hansha 2 years ago
parent 556fd410c8
commit dc04eea7c6

@ -90,6 +90,8 @@ spring:
# token配置 # token配置
token: token:
#是否允许账户多终端同时登录true允许 false不允许
soloLogin: true
# 令牌自定义标识 # 令牌自定义标识
header: Authorization header: Authorization
# 令牌密钥 # 令牌密钥

@ -1,8 +1,9 @@
package com.da.common.constant; package com.da.common.constant;
import java.util.Locale;
import io.jsonwebtoken.Claims; import io.jsonwebtoken.Claims;
import java.util.Locale;
/** /**
* *
* *
@ -10,6 +11,11 @@ import io.jsonwebtoken.Claims;
*/ */
public class Constants public class Constants
{ {
/**
* redis key
*/
public static final String LOGIN_USERID_KEY = "login_userid:";
/** /**
* UTF-8 * UTF-8
*/ */

@ -1,23 +1,23 @@
package com.da.framework.security.handle; package com.da.framework.security.handle;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSON;
import com.da.common.constant.Constants; import com.da.common.constant.Constants;
import com.da.common.core.domain.AjaxResult; import com.da.common.core.domain.AjaxResult;
import com.da.common.core.domain.model.LoginUser; import com.da.common.core.domain.model.LoginUser;
import com.da.common.utils.MessageUtils;
import com.da.common.utils.ServletUtils; import com.da.common.utils.ServletUtils;
import com.da.common.utils.StringUtils; import com.da.common.utils.StringUtils;
import com.da.framework.manager.AsyncManager; import com.da.framework.manager.AsyncManager;
import com.da.framework.manager.factory.AsyncFactory; import com.da.framework.manager.factory.AsyncFactory;
import com.da.framework.web.service.TokenService; import com.da.framework.web.service.TokenService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/** /**
* 退 * 退
@ -36,7 +36,7 @@ public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler
* @return * @return
*/ */
@Override @Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) /*public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException, ServletException throws IOException, ServletException
{ {
LoginUser loginUser = tokenService.getLoginUser(request); LoginUser loginUser = tokenService.getLoginUser(request);
@ -49,5 +49,23 @@ public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler
AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, MessageUtils.message("user.logout.success"))); AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, MessageUtils.message("user.logout.success")));
} }
ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.success(MessageUtils.message("user.logout.success")))); ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.success(MessageUtils.message("user.logout.success"))));
}*/
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException, ServletException
{
LoginUser loginUser = tokenService.getLoginUser(request);
if (StringUtils.isNotNull(loginUser))
{
String userName = loginUser.getUsername();
// 删除用户缓存记录(旧方法)
//tokenService.delLoginUser(loginUser.getToken());
// 删除用户缓存记录 只允许单用户登录(关键)
tokenService.delLoginUser(loginUser.getToken(), loginUser.getUser().getUserId());
// 记录用户退出日志
AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, "退出成功"));
}
ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.success("退出成功")));
} }
} }

@ -1,12 +1,5 @@
package com.da.framework.web.service; package com.da.framework.web.service;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import com.da.common.constant.CacheConstants; import com.da.common.constant.CacheConstants;
import com.da.common.constant.Constants; import com.da.common.constant.Constants;
import com.da.common.constant.UserConstants; import com.da.common.constant.UserConstants;
@ -14,11 +7,7 @@ import com.da.common.core.domain.entity.SysUser;
import com.da.common.core.domain.model.LoginUser; import com.da.common.core.domain.model.LoginUser;
import com.da.common.core.redis.RedisCache; import com.da.common.core.redis.RedisCache;
import com.da.common.exception.ServiceException; import com.da.common.exception.ServiceException;
import com.da.common.exception.user.BlackListException; import com.da.common.exception.user.*;
import com.da.common.exception.user.CaptchaException;
import com.da.common.exception.user.CaptchaExpireException;
import com.da.common.exception.user.UserNotExistsException;
import com.da.common.exception.user.UserPasswordNotMatchException;
import com.da.common.utils.DateUtils; import com.da.common.utils.DateUtils;
import com.da.common.utils.MessageUtils; import com.da.common.utils.MessageUtils;
import com.da.common.utils.StringUtils; import com.da.common.utils.StringUtils;
@ -28,6 +17,15 @@ import com.da.framework.manager.factory.AsyncFactory;
import com.da.framework.security.context.AuthenticationContextHolder; import com.da.framework.security.context.AuthenticationContextHolder;
import com.da.system.service.ISysConfigService; import com.da.system.service.ISysConfigService;
import com.da.system.service.ISysUserService; import com.da.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/** /**
* *
@ -37,6 +35,9 @@ import com.da.system.service.ISysUserService;
@Component @Component
public class SysLoginService public class SysLoginService
{ {
// 是否允许账户多终端同时登录true允许 false不允许
@Value("${token.soloLogin}")
private boolean soloLogin;
@Autowired @Autowired
private TokenService tokenService; private TokenService tokenService;
@ -96,6 +97,21 @@ public class SysLoginService
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"))); AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
LoginUser loginUser = (LoginUser) authentication.getPrincipal(); LoginUser loginUser = (LoginUser) authentication.getPrincipal();
recordLoginInfo(loginUser.getUserId()); recordLoginInfo(loginUser.getUserId());
//---------------------------------------添加如下代码,验证如果用户不允许多终端同时登录,清除缓存信息
if (!soloLogin)
{
// 如果用户不允许多终端同时登录,清除缓存信息
String userIdKey = Constants.LOGIN_USERID_KEY + loginUser.getUser().getUserId();
String userKey = redisCache.getCacheObject(userIdKey);
if (StringUtils.isNotEmpty(userKey))
{
redisCache.deleteObject(userIdKey);
redisCache.deleteObject(userKey);
}
}
//----------------新增代码结束
// 生成token // 生成token
return tokenService.createToken(loginUser); return tokenService.createToken(loginUser);
} }

@ -1,14 +1,5 @@
package com.da.framework.web.service; package com.da.framework.web.service;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.da.common.constant.CacheConstants; import com.da.common.constant.CacheConstants;
import com.da.common.constant.Constants; import com.da.common.constant.Constants;
import com.da.common.core.domain.model.LoginUser; import com.da.common.core.domain.model.LoginUser;
@ -22,6 +13,16 @@ import eu.bitwalker.useragentutils.UserAgent;
import io.jsonwebtoken.Claims; import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts; import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.SignatureAlgorithm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/** /**
* token * token
@ -33,6 +34,10 @@ public class TokenService
{ {
private static final Logger log = LoggerFactory.getLogger(TokenService.class); private static final Logger log = LoggerFactory.getLogger(TokenService.class);
// 是否允许账户多终端同时登录true允许 false不允许
@Value("${token.soloLogin}")
private boolean soloLogin;
// 令牌自定义标识 // 令牌自定义标识
@Value("${token.header}") @Value("${token.header}")
private String header; private String header;
@ -96,15 +101,29 @@ public class TokenService
/** /**
* *
*/ */
public void delLoginUser(String token) /* public void delLoginUser(String token)
{ {
if (StringUtils.isNotEmpty(token)) if (StringUtils.isNotEmpty(token))
{ {
String userKey = getTokenKey(token); String userKey = getTokenKey(token);
redisCache.deleteObject(userKey); redisCache.deleteObject(userKey);
} }
}*/
public void delLoginUser(String token, Long userId)
{
if (StringUtils.isNotEmpty(token))
{
String userKey = getTokenKey(token);
redisCache.deleteObject(userKey);
}
if (!soloLogin && StringUtils.isNotNull(userId))
{
String userIdKey = getUserIdKey(userId);
redisCache.deleteObject(userIdKey);
}
} }
/** /**
* *
* *
@ -144,13 +163,28 @@ public class TokenService
* *
* @param loginUser * @param loginUser
*/ */
public void refreshToken(LoginUser loginUser) /* public void refreshToken(LoginUser loginUser)
{
loginUser.setLoginTime(System.currentTimeMillis());
loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);
// 根据uuid将loginUser缓存
String userKey = getTokenKey(loginUser.getToken());
redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
}*/
public String refreshToken(LoginUser loginUser)
{ {
loginUser.setLoginTime(System.currentTimeMillis()); loginUser.setLoginTime(System.currentTimeMillis());
loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE); loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);
// 根据uuid将loginUser缓存 // 根据uuid将loginUser缓存
String userKey = getTokenKey(loginUser.getToken()); String userKey = getTokenKey(loginUser.getToken());
redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES); redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
if (!soloLogin)
{
// 缓存用户唯一标识,防止同一帐号,同时登录
String userIdKey = getUserIdKey(loginUser.getUser().getUserId());
redisCache.setCacheObject(userIdKey, userKey, expireTime, TimeUnit.MINUTES);
}
return userKey;
} }
/** /**
@ -168,6 +202,11 @@ public class TokenService
loginUser.setOs(userAgent.getOperatingSystem().getName()); loginUser.setOs(userAgent.getOperatingSystem().getName());
} }
private String getUserIdKey(Long userId)
{
return Constants.LOGIN_USERID_KEY + userId;
}
/** /**
* *
* *

@ -93,7 +93,8 @@ service.interceptors.response.use(res => {
isRelogin.show = false; isRelogin.show = false;
}); });
} }
return Promise.reject('无效的会话,或者会话已过期,请重新登录。') //return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
return Promise.reject('会话已过期,或者被挤下线,请重新登录。')
} else if (code === 500) { } else if (code === 500) {
Message({ message: msg, type: 'error' }) Message({ message: msg, type: 'error' })
return Promise.reject(new Error(msg)) return Promise.reject(new Error(msg))

Loading…
Cancel
Save