package com.vci.web.service.impl;
|
|
import com.vci.client.mw.ClientSessionUtility;
|
import com.vci.constant.CacheNameConstant;
|
import com.vci.corba.common.PLException;
|
import com.vci.corba.common.data.InvocationInfo;
|
import com.vci.corba.omd.data.AttributeValue;
|
import com.vci.starter.web.annotation.log.VciUnLog;
|
import com.vci.starter.web.constant.TokenKeyConstant;
|
import com.vci.starter.web.exception.VciBaseException;
|
import com.vci.starter.web.interceptor.VciSessionForLoginI;
|
import com.vci.starter.web.pagemodel.SessionInfo;
|
import com.vci.starter.web.pagemodel.TokenVO;
|
import com.vci.starter.web.redis.RedisService;
|
import com.vci.starter.web.util.*;
|
import com.vci.web.properties.WebProperties;
|
import com.vci.web.service.WebBoServiceI;
|
import com.vci.web.util.PlatformClientUtil;
|
import com.vci.web.util.WebUtil;
|
import org.apache.commons.lang3.StringUtils;
|
import org.slf4j.Logger;
|
import org.slf4j.LoggerFactory;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.stereotype.Service;
|
import org.springframework.util.CollectionUtils;
|
|
import javax.annotation.Resource;
|
import javax.servlet.http.HttpServletRequest;
|
import java.util.ArrayList;
|
import java.util.HashMap;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.concurrent.TimeUnit;
|
|
/**
|
* 会话存储的服务
|
* @author weidy
|
* @date 2021/2/18
|
*/
|
@Service
|
@VciUnLog
|
public class SmSessionForLoginImpl implements VciSessionForLoginI {
|
|
/**
|
* 日志
|
*/
|
private Logger logger = LoggerFactory.getLogger(getClass());
|
|
/**
|
* 配置信息
|
*/
|
@Autowired
|
private WebProperties webProperties;
|
|
/**
|
* 业务类型服务
|
*/
|
@Autowired
|
private WebBoServiceI boService;
|
|
/**
|
* 平台的调用类
|
*/
|
@Autowired
|
private PlatformClientUtil platformClientUtil;
|
|
/**
|
* redis服务
|
*/
|
@Resource
|
private RedisService redisService;
|
|
/**
|
* 检查用户是否登录
|
*
|
* @param userId 用户名
|
* @return 为空表示没有登录
|
*/
|
@Override
|
public String checkIsLogined(String userId) {
|
WebUtil.alertNotNull(userId,"用户名");
|
List<Map> dataList = boService.queryBySqlForMap("select JSONSTRING as JSONSTRING from VCI_SESSIONINFO where userid ='" + userId.trim() + "'", new HashMap<>());
|
if(!CollectionUtils.isEmpty(dataList)) {
|
Map data = dataList.get(0);
|
SessionInfo sessionInfo = WebUtil.jsonString2JavaBean((String)data.getOrDefault("JSONSTRING",""),SessionInfo.class);
|
return "在ip为" + sessionInfo.getIp() + "的地方已经登录";
|
}
|
return "";
|
}
|
|
/**
|
* 强制用户下线
|
*
|
* @param userId 用户名
|
*/
|
@Override
|
public void popUser(String userId) {
|
WebUtil.alertNotNull(userId,"用户名");
|
try{
|
platformClientUtil.getBOFactoryService().executeUpdateSql("delete from VCI_SESSIONINFO where userid ='" + userId.trim() + "'");
|
}catch (PLException e){
|
throw WebUtil.getVciBaseException(e);
|
}
|
}
|
|
/**
|
* 将会话信息存储到数据库中------
|
*
|
* @param sessionInfo 会话信息
|
*/
|
@Override
|
@Deprecated
|
public void saveSessionInfo(SessionInfo sessionInfo) {
|
WebUtil.alertNotNull(sessionInfo,"会话信息");
|
try {
|
AttributeValue[] attrs = new AttributeValue[3];
|
attrs[0] = new AttributeValue("0", sessionInfo.getUserId());
|
attrs[1] = new AttributeValue("1", sessionInfo.getToken());
|
attrs[2] = new AttributeValue("2", WebUtil.getJSONStringWithDateFormat(sessionInfo));
|
platformClientUtil.getBOFactoryService().executeUpdateSqlByParams(" insert into VCI_SESSIONINFO (USERID, TOKEN, JSONSTRING,lastRequestTime\n" +
|
" )\n" +
|
" VALUES (?,?,?," + System.currentTimeMillis() + " )", attrs);
|
}catch (PLException e){
|
throw WebUtil.getVciBaseException(e);
|
}
|
}
|
|
/**
|
* 校验请求是否符合权限验证
|
* 包含1,系统是否可以访问当前服务或者接口
|
* 2, 用户是否有权限访问当前服务
|
* 3, 用户是否有权限访问当前数据
|
*
|
* @param request 请求对象
|
* @param systemPrivateToken 系统的许可码
|
* @param sessionInfo 当前用户会话对象
|
* @param handler 执行对象
|
* @return true表示有权限,false表示没权限
|
* @throws VciBaseException 没有权限的时候会抛出异常
|
*/
|
@Override
|
public boolean checkRequestRights(HttpServletRequest request, String systemPrivateToken, SessionInfo sessionInfo, Object handler) throws VciBaseException {
|
return true;
|
}
|
|
/**
|
* 更新请求时间
|
*
|
* @param userToken 用户token
|
*/
|
@Override
|
public void updateRequestTime(String userToken) {
|
WebUtil.alertNotNull(userToken,"会话许可码");
|
//说明是jwt的token
|
String jwtToken = getSessionTokenKeyInRedis(userToken);
|
if(StringUtils.isBlank(jwtToken)){
|
jwtToken = userToken;
|
}
|
SessionInfo sessionInfo = redisService.getCacheObject(jwtToken);
|
sessionInfo.setLastLoginTime(VciDateUtil.getNowTime());
|
redisService.setCacheObject(jwtToken, sessionInfo, webProperties.getClientSessionAliveMax()!=0?webProperties.getClientSessionAliveMax(): TokenKeyConstant.EXPIRATION, TimeUnit.MINUTES);
|
}
|
|
/**
|
* 根据token获取用户的对象
|
*
|
* @param userToken 用户token
|
* @return 用户会话对象
|
*/
|
@Override
|
public SessionInfo getSessionInfoByToken(String userToken) {
|
WebUtil.alertNotNull(userToken,"许可的信息");
|
SessionInfo sessionInfo = null;
|
if(StringUtils.isNotBlank(userToken)){
|
if(userToken.startsWith(TokenKeyConstant.TOKEN_KEY_PREFIX_IN_REDIS)){
|
sessionInfo = redisService.getCacheObject(userToken);
|
if(sessionInfo == null){
|
throw new VciBaseException("token已过期!");
|
}
|
}else{
|
//说明是jwt的token
|
String jwtToken = getSessionTokenKeyInRedis(userToken);
|
if(StringUtils.isBlank(jwtToken)){
|
jwtToken = userToken;
|
}
|
sessionInfo = redisService.getCacheObject(jwtToken);
|
if(sessionInfo == null){
|
throw new VciBaseException("token已过期!");
|
}
|
}
|
}
|
return sessionInfo;
|
}
|
|
/**
|
* 退出登录
|
*
|
* @param userToken 用户的会话许可
|
*/
|
@Override
|
public void logout(String userToken) {
|
//TODO 根据情况,单独处理
|
}
|
|
/**
|
* 根据token获取用户在系统中还可以存在的时间
|
* @param userToken userToken 用户的会话许可
|
* @return 用户在系统中还可以存在的时间(毫秒)
|
*/
|
@Override
|
public long getCanAliveTime(String userToken) {
|
VciBaseUtil.alertNotNull(userToken,"用户会话许可(令牌)");
|
List<Map> dataList = boService.queryBySqlForMap("select lastRequestTime as LASTREQUESTTIME from VCI_SESSIONINFO where TOKEN ='" + userToken.trim() + "'", new HashMap<>());
|
if(!CollectionUtils.isEmpty(dataList)) {
|
Map data = dataList.get(0);
|
long lastTime = WebUtil.getLong(data.get("LASTREQUESTTIME").toString());
|
long currentTime = System.currentTimeMillis();
|
long canAliveTime = lastTime + (webProperties.getClientSessionAliveMax()*60*1000) - currentTime;
|
return canAliveTime;
|
}
|
return 0;
|
}
|
|
/**
|
* 删除超时的会话的信息
|
*/
|
@Scheduled(fixedDelay=60000)
|
public void deleteTimeoutSession(){
|
long now = System.currentTimeMillis();
|
if(webProperties.getClientSessionAliveMax() > 0) {
|
long lastValidTime = now - webProperties.getClientSessionAliveMax() * 60000;
|
if (logger.isDebugEnabled()) {
|
logger.debug("开始执行扫描超时的会话信息,其中当前时间为{},会话最后访问的有效时间应该为{}", now, lastValidTime);
|
}
|
List<Map> invalidSessionList = boService.queryBySqlForMap("select token as TOKEN from VCI_SESSIONINFO where lastRequestTime<= " + lastValidTime, null);
|
if (!CollectionUtils.isEmpty(invalidSessionList)) {
|
List<String> tokenList = new ArrayList<>();
|
invalidSessionList.stream().forEach(map -> {
|
tokenList.add(map.get("TOKEN").toString());
|
});
|
WebUtil.switchCollectionForOracleIn(tokenList).stream().forEach(tokens -> {
|
try {
|
platformClientUtil.getBOFactoryService().executeUpdateSql("delete from VCI_SESSIONINFO where TOKEN in (" + WebUtil.toInSql(tokens.toArray(new String[0])) + ")");
|
} catch (PLException e) {
|
if (logger.isErrorEnabled()) {
|
logger.error("删除会话信息", e);
|
}
|
}
|
});
|
}
|
if (logger.isDebugEnabled()) {
|
logger.debug("开始执行扫描超时的会话信息完成,删除了{}条数据", invalidSessionList == null ? 0 : invalidSessionList.size());
|
}
|
}
|
}
|
|
/**
|
* 创建许可的信息,并存储到缓存中
|
*
|
* @param sessionInfo session的信息
|
* @return 许可信息
|
*/
|
@Override
|
public TokenVO createToken(SessionInfo sessionInfo) {
|
return createToken(TokenKeyConstant.TOKEN_KEY_PREFIX_IN_REDIS, sessionInfo);
|
}
|
|
/**
|
* 创建许可的信息,并存储到缓存中
|
* @param key token在redis中的key
|
* @param sessionInfo session的信息
|
* @return 许可信息
|
*/
|
@Override
|
public TokenVO createToken(String key, SessionInfo sessionInfo) {
|
if(StringUtils.isBlank(sessionInfo.getToken())) {
|
String token = Md5.md5(VciBaseUtil.getPk() + "_" + sessionInfo.getUserId());
|
sessionInfo.setToken(token);
|
}
|
if(StringUtils.isBlank(key)){
|
key = TokenKeyConstant.TOKEN_KEY_PREFIX_IN_REDIS;
|
}
|
refreshToken(key, sessionInfo);
|
Map<String,Object> claimsMap = new HashMap<>();
|
claimsMap.put(TokenKeyConstant.JWT_TOKEN_KEY,sessionInfo.getToken());
|
claimsMap.put(TokenKeyConstant.JWT_USER_KEY,sessionInfo.getUserOid());
|
claimsMap.put(TokenKeyConstant.JWT_USER_NAME_KEY,sessionInfo.getUserName());
|
claimsMap.put(TokenKeyConstant.JWT_USER_CODE_KEY,sessionInfo.getUserId());
|
TokenVO tokenVO = new TokenVO();
|
tokenVO.setAccessToken(JwtUtils.createToken(claimsMap));
|
tokenVO.setExpireTime(TokenKeyConstant.EXPIRATION);
|
return tokenVO;
|
}
|
|
/**
|
* 刷新缓存中的token
|
* @param sessionInfo session的信息
|
*/
|
@Override
|
public void refreshToken(SessionInfo sessionInfo) {
|
refreshToken(TokenKeyConstant.TOKEN_KEY_PREFIX_IN_REDIS, sessionInfo);
|
}
|
|
/**
|
* 刷新缓存中的token
|
* @param key token在redis中的key
|
* @param sessionInfo session的信息
|
*/
|
@Override
|
public void refreshToken(String key, SessionInfo sessionInfo) {
|
if(sessionInfo!=null && StringUtils.isNotBlank(sessionInfo.getToken())){
|
if(StringUtils.isBlank(key)){
|
key = TokenKeyConstant.TOKEN_KEY_PREFIX_IN_REDIS;
|
}
|
String redisKey = key + sessionInfo.getToken();
|
redisService.setCacheObject(redisKey, sessionInfo, webProperties.getClientSessionAliveMax()!=0?webProperties.getClientSessionAliveMax(): TokenKeyConstant.EXPIRATION, TimeUnit.MINUTES);
|
|
//因为可能需要退出登录,或同一用户只能在线一个,故需要存储,用户和jwtToken的关系
|
String tokenKey = CacheNameConstant.cacheKey(CacheNameConstant.USERID_TOKEN_KEY,sessionInfo.getUserId());
|
redisService.setCacheObject(tokenKey, redisKey, webProperties.getClientSessionAliveMax()!=0?webProperties.getClientSessionAliveMax(): TokenKeyConstant.EXPIRATION, TimeUnit.MINUTES);
|
}
|
}
|
|
/**
|
* jwt的token改成
|
* @param jwtToken jwt的许可
|
* @return 在redis里的信息
|
*/
|
private String getSessionTokenKeyInRedis(String jwtToken) {
|
if(StringUtils.isBlank(jwtToken)){
|
return "";
|
}
|
String key = TokenKeyConstant.TOKEN_KEY_PREFIX_IN_REDIS;
|
if(ControllerUtil.urlDecode(jwtToken).startsWith(key)){
|
return ControllerUtil.urlDecode(jwtToken);
|
}
|
String userToken = JwtUtils.getUserToken(jwtToken);
|
return TokenKeyConstant.TOKEN_KEY_PREFIX_IN_REDIS + userToken;
|
}
|
|
/**
|
* 将token放入平台中
|
*
|
* @param sessionInfo
|
*/
|
@Override
|
public void initInvocationInfo(SessionInfo sessionInfo) {
|
InvocationInfo vcii = new InvocationInfo();
|
vcii.setToken(sessionInfo.getToken());
|
ClientSessionUtility.setInvocationInThread(vcii);
|
}
|
}
|