package com.vci.web.service.impl;
|
|
import com.vci.client.mw.ClientSessionUtility;
|
import com.vci.corba.common.PLException;
|
import com.vci.corba.common.data.InvocationInfo;
|
import com.vci.corba.framework.data.DeptInfo;
|
import com.vci.corba.framework.data.LoginResult;
|
import com.vci.corba.framework.data.LoginState;
|
import com.vci.corba.framework.data.MachineInfo;
|
import com.vci.frameworkcore.ajaxTask.SmUserUnLockTask;
|
import com.vci.frameworkcore.ajaxTask.SmUserUnLockTaskManager;
|
import com.vci.frameworkcore.compatibility.ISmFunctionQueryService;
|
import com.vci.frameworkcore.compatibility.SmRoleQueryServiceI;
|
import com.vci.frameworkcore.compatibility.SmUserQueryServiceI;
|
import com.vci.frameworkcore.enumpck.ResourceControlTypeEnum;
|
import com.vci.frameworkcore.pagemodel.SmFunctionVO;
|
import com.vci.frameworkcore.pagemodel.SmUserVO;
|
import com.vci.frameworkcore.properties.VciSecurityManageProperties;
|
import com.vci.starter.web.annotation.bus.VciLoginAfter;
|
import com.vci.starter.web.annotation.bus.VciLogoutBefore;
|
import com.vci.starter.web.annotation.bus.VciLogoutPlugin;
|
import com.vci.starter.web.exception.VciBaseException;
|
import com.vci.starter.web.interceptor.VciSessionForLoginI;
|
import com.vci.starter.web.pagemodel.RequestClientInfo;
|
import com.vci.starter.web.pagemodel.SessionInfo;
|
import com.vci.starter.web.pagemodel.TokenVO;
|
import com.vci.starter.web.util.*;
|
import com.vci.web.bo.LoginResultBO;
|
import com.vci.web.constant.CacheNameConstant;
|
import com.vci.web.dto.LoginUserDTO;
|
import com.vci.web.properties.WebProperties;
|
import com.vci.web.redis.RedisService;
|
import com.vci.web.service.LoginServiceI;
|
import com.vci.web.util.PlatformClientUtil;
|
import org.apache.commons.lang3.StringUtils;
|
import org.slf4j.Logger;
|
import org.slf4j.LoggerFactory;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Service;
|
import org.springframework.util.CollectionUtils;
|
|
import javax.annotation.Resource;
|
import java.lang.reflect.Method;
|
import java.util.Date;
|
import java.util.List;
|
import java.util.Map;
|
|
import static com.vci.frameworkcore.constant.FrameWorkBusLangCodeConstant.*;
|
|
/**
|
* 登录的服务
|
* @author weidy
|
* @date 2020/1/29
|
*/
|
@Service
|
public class LoginServiceImpl implements LoginServiceI {
|
|
/**
|
* 日志
|
*/
|
private Logger logger = LoggerFactory.getLogger(getClass());
|
|
/**
|
* 会话处理
|
*/
|
@Resource
|
private VciSessionForLoginI sessionForLogin;
|
|
/**
|
* 解锁任务
|
*/
|
@Resource
|
private SmUserUnLockTaskManager unLockTaskManager;
|
|
/**
|
* 权限管理的相关配置
|
*/
|
@Resource
|
private VciSecurityManageProperties securityManageProperties;
|
|
/**
|
* 用户查询服务,可以兼容老平台
|
*/
|
@Resource
|
private SmUserQueryServiceI userQueryService;
|
|
/**
|
* 角色的查询服务,可以兼容老平台
|
*/
|
@Resource
|
private SmRoleQueryServiceI roleQueryService;
|
|
/**
|
* 权限的查询服务,可以兼容老平台
|
*/
|
@Resource
|
private ISmFunctionQueryService functionQueryService;
|
|
/**
|
* redis服务
|
*/
|
@Resource
|
private RedisService redisService;
|
|
/**
|
* 客户端配置文件
|
*/
|
@Resource
|
private WebProperties webProperties;
|
|
/**
|
* 平台调用客户端
|
*/
|
@Resource
|
private PlatformClientUtil platformClientUtil;
|
|
/**
|
* 执行登录
|
* @param userDTO 登录信息
|
* @param clientInfo 请求的客户端的信息
|
* @throws VciBaseException 登录发生异常的时候出现了错误
|
*/
|
@Override
|
public LoginResultBO login(LoginUserDTO userDTO, RequestClientInfo clientInfo) throws VciBaseException {
|
return login(userDTO,clientInfo,true);
|
}
|
|
/**
|
* 登录
|
* @param userDTO 用户的数据传输对象
|
* @param clientInfo 客户端的信息
|
* @param checkPassword 是否校验密码
|
* @return 执行结果
|
* @throws VciBaseException 参数错误,用户不能登录等会抛出异常
|
*/
|
private LoginResultBO login(LoginUserDTO userDTO, RequestClientInfo clientInfo, boolean checkPassword) throws VciBaseException {
|
LoginResultBO loginResult = new LoginResultBO();
|
loginResult.setSuccess(false);
|
//1.判断用户的基本信息
|
VciBaseUtil.alertNotNull(userDTO, "登录信息", userDTO.getUserId(), "用户账号");
|
if (checkPassword) {
|
VciBaseUtil.alertNotNull(userDTO.getPassword(), "登录密码");
|
}
|
|
//需要看看是否已经登录了
|
String userIdTokenKey = CacheNameConstant.cacheKey(CacheNameConstant.USERID_TOKEN_KEY, userDTO.getUserId().trim());
|
if(redisService.hasKey(userIdTokenKey) && !userDTO.isForceLogin() && securityManageProperties.isUserOneLogin()){
|
loginResult.setFailCode(USER_IS_LOGINED);
|
loginResult.setFailMsg("当前用户已经在其他地方登录!");
|
return loginResult;
|
}
|
//说明已经登录了,那应该取消原来的登录
|
if (redisService.hasKey(userIdTokenKey) && userDTO.isForceLogin() && securityManageProperties.isUserOneLogin()) {
|
String tokenKey = redisService.getCacheObject(userIdTokenKey);
|
redisService.deleteObject(tokenKey);
|
redisService.deleteObject(userIdTokenKey);
|
}
|
|
//2.获取用户的对象.
|
SmUserVO user = getUserByUserId(userDTO.getUserId().trim());
|
if (user == null || StringUtils.isBlank(user.getOid())) {
|
loginResult.setFailCode(USER_NOT_FOUND);
|
loginResult.setFailMsgArray(new String[]{userDTO.getUserId()});
|
return loginResult;
|
}
|
|
//3、判断密码是否正确
|
if (checkPassword) {
|
boolean passwordIsEqual = userQueryService.checkPasswordEqual(userDTO.getPassword(), user.getOid());
|
if (!passwordIsEqual) {
|
if (logger.isDebugEnabled()) {
|
logger.debug("{}密码不正确", user.getId());
|
}
|
}
|
}
|
|
//4、调用平台登录接口,进行登录
|
MachineInfo machine = getMachieInfo(clientInfo);
|
machine.country = clientInfo.getCountry();
|
machine.language = clientInfo.getLanguage();
|
machine.osUser = clientInfo.getOsUser();
|
machine.machine = clientInfo.getMachine();
|
|
String token = null;
|
try {
|
LoginResult chkRes = platformClientUtil.getFrameworkService().checkLogin(userDTO.getUserId(),userDTO.getPassword(), machine);
|
loginResult.setFailCode(getErrorCode(chkRes));
|
loginResult.setFailMsgArray(new String[]{userDTO.getUserId(), String.valueOf(chkRes.auxInfo)});
|
if(chkRes.state == LoginState.Error || chkRes.state == LoginState.Locked || chkRes.state == LoginState.Freeze){
|
return loginResult;
|
}
|
token = chkRes.token;
|
} catch (Exception e) {
|
loginResult.setFailCode(SYSTEM_ERROR);
|
loginResult.setFailMsgArray(new String[]{userDTO.getUserId()});
|
return loginResult;
|
}
|
if(StringUtils.isBlank(token)){
|
loginResult.setFailMsg(TOKEN_EMPTY);
|
loginResult.setFailMsgArray(new String[]{userDTO.getUserId()});
|
return loginResult;
|
}
|
|
//如果用户已经被停用和锁定,不能登录
|
//如果用户的失效日期已经超过了当前时间,不能登录
|
//只有新平台的用户才判断失效
|
/**if (FrameworkDataLCStatus.DISABLED.getValue().equals(user.getLcStatus())) {
|
loginResult.setFailCode(USER_IS_DISABLED);
|
loginResult.setFailMsgArray(new String[]{userDTO.getUserId()});
|
return loginResult;
|
}
|
if (userQueryService.checkUserLock(user, user.getPwdWrongCount())) {
|
loginResult.setFailCode(USER_IS_LOCK);
|
loginResult.setFailMsgArray(new String[]{userDTO.getUserId()});
|
return loginResult;
|
}
|
if (user.getDisabledate() != null) {
|
//2021版本才有这个属性的值,当前这个没有这个值
|
Date disableDate = VciDateUtil.addOrSubDate(user.getDisabledate(), Calendar.DATE, 1);
|
if (disableDate != null && disableDate.getTime() < System.currentTimeMillis()) {
|
loginResult.setFailCode(USER_MORE_THAN_DISABLE_DATE);
|
loginResult.setFailMsgArray(new String[]{userDTO.getUserId()});
|
return loginResult;
|
}
|
}
|
|
SmPasswordStrategyVO passwordStrategyVO = userQueryService.getPasswordStrategyVOByUserOid(user.getOid());
|
if (checkPassword) {
|
boolean passwordIsEqual = userQueryService.checkPasswordEqual(userDTO.getPassword(), user.getOid());
|
//3.判断用户的密码是否正确
|
if (!passwordIsEqual) {
|
//前端需要先md5一次,然后后台再MD5一次,
|
if (logger.isDebugEnabled()) {
|
logger.debug("{}密码不正确", user.getId());
|
}
|
if (passwordStrategyVO == null) {
|
//可能数据问题没有设置密码策略
|
passwordStrategyVO = new SmPasswordStrategyVO();
|
passwordStrategyVO.setRetryTime(6);
|
passwordStrategyVO.setLockTime(30);
|
}
|
if (passwordStrategyVO.getRetryTime() <= (user.getPwdWrongCount() + 1)) {
|
user.setLockFlag(true);
|
updateUserPwdWrongCount(user.getOid(), user.getPwdWrongCount() + 1);
|
addUserToUnLock(userDTO.getUserId(), passwordStrategyVO.getLockTime());
|
updateUserPwdWrongCount(user.getOid(), user.getPwdWrongCount() + 1);
|
loginResult.setFailCode(USER_PWD_LOCK);
|
loginResult.setFailMsgArray(new String[]{userDTO.getUserId(), passwordStrategyVO.getLockTime() + ""});
|
return loginResult;
|
} else {
|
//还没有到锁定的次数
|
updateUserPwdWrongCount(user.getOid(), user.getPwdWrongCount() + 1);
|
//5, 这是第一次错误,剩下的是 5- (0+1)
|
loginResult.setFailCode(USER_PWD_NOT_EQUAL);
|
loginResult.setFailMsgArray(new String[]{userDTO.getUserId(), (passwordStrategyVO.getRetryTime() - (user.getPwdWrongCount() + 1)) + ""});
|
return loginResult;
|
}
|
}
|
}
|
|
//检查是否该修改密码
|
if (!clientInfo.isSso() && checkPassword) {
|
//最后修改时间+ 失效时间,大于等于当前日期,则需要马上修改密码
|
Date currentDay = null;
|
try {
|
currentDay = VciDateUtil.getNow(VciDateUtil.DateFormat);
|
} catch (Throwable e) {
|
if (logger.isErrorEnabled()) {
|
logger.error("获取当前日期", e);
|
}
|
}
|
if (currentDay != null && passwordStrategyVO != null && passwordStrategyVO.getValidDay() != null) {
|
Date inValidDay = null;
|
if (user.getLastModifyPasswordTime() == null) {
|
//重来没有登录过
|
loginResult.setMustChangePassword(true);
|
} else {
|
inValidDay = VciDateUtil.addOrSubDate(user.getLastModifyPasswordTime(), Calendar.DATE, passwordStrategyVO.getValidDay());
|
if (inValidDay.getTime() <= (currentDay).getTime()) {
|
loginResult.setMustChangePassword(true);
|
}
|
}
|
if (!loginResult.isMustChangePassword()) {
|
if (VciDateUtil.addOrSubDate(inValidDay, Calendar.DATE, -(passwordStrategyVO.getRemindDay())).getTime()
|
<= (currentDay).getTime()) {
|
//您的密码还有{0}天过期,请及时修改密码
|
long remainDay = VciDateUtil.getDaySub(inValidDay, currentDay);
|
loginResult.setPasswordInfo(MessageFormat.format(PASSWORD_REMAIN_DAY, new String[]{String.valueOf(remainDay)}));
|
}
|
}
|
}
|
}*/
|
|
//说明密码正确的
|
if (logger.isDebugEnabled()) {
|
logger.debug("{}的密码正确", user.getId());
|
}
|
user.setLastLoginTime(new Date());
|
user.setPwdWrongCount(0);
|
|
SessionInfo sessionInfo = new SessionInfo();
|
sessionInfo.setToken(token);
|
|
//初始化平台的token
|
sessionForLogin.initInvocationInfo(sessionInfo);
|
|
//拷贝用户的新到session会话中
|
copyUser2SessionInfo(user, sessionInfo, userDTO.getLangCode());
|
//拷贝请求信息到session会话中
|
copyRequest2SessionInfo(clientInfo, sessionInfo);
|
|
//获取人员所属的部门信息
|
try {
|
DeptInfo deptInfo = platformClientUtil.getFrameworkService().fetchDeptByUserId(user.getOid());
|
sessionInfo.setDeptOid(deptInfo.id);
|
sessionInfo.setDeptName(deptInfo.name);
|
sessionInfo.setDeptNum(deptInfo.num);
|
} catch (PLException e) {
|
throw new VciBaseException("获取用户所属部门失败:"+e.getMessage());
|
}
|
|
/** //查询所有的角色
|
List<SmRoleVO> roleVOList = roleQueryService.listRoleByUserOid(user.getOid(), null);
|
if (!CollectionUtils.isEmpty(roleVOList)) {
|
Map<String, String> roleOidNameMap = roleVOList.stream().collect(Collectors.toMap(s -> s.getOid(), t -> t.getName()));
|
sessionInfo.setRolesName(roleOidNameMap);
|
} else {
|
sessionInfo.setRolesName(new HashMap());
|
}
|
//查询所有的权限
|
List<SmFunctionVO> functionVOList = functionQueryService.listFunctionByUserOid(user.getOid(), null, ResourceControlTypeEnum.BS);
|
if (!CollectionUtils.isEmpty(functionVOList)) {
|
List<String> functionOidList = functionVOList.stream().map(s -> s.getOid()).collect(Collectors.toList());
|
sessionInfo.setFunctionOids(functionOidList);
|
} else {
|
sessionInfo.setFunctionOids(new ArrayList());
|
}*/
|
|
//添加到会话信息
|
TokenVO tokenVO = saveSessionInfo(sessionInfo);
|
loginResult.setTokenVO(tokenVO);
|
|
loginResult.setSuccess(true);
|
return loginResult;
|
}
|
|
private MachineInfo getMachieInfo(RequestClientInfo clientInfo) {
|
MachineInfo machine = new MachineInfo();
|
machine.country = clientInfo.getCountry();
|
machine.language = clientInfo.getLanguage();
|
machine.osUser = clientInfo.getOsUser();
|
machine.machine = clientInfo.getMachine();
|
return machine;
|
}
|
|
/**
|
* 获取用户信息
|
* @param userId userId
|
* @Return com.vci.frameworkcore.pagemodel.SmUserVO
|
*/
|
private SmUserVO getUserByUserId(String userId) {
|
return userQueryService.getUserByUserId(userId);
|
}
|
|
|
/**
|
* 单点登录
|
*
|
* @param userDTO 登录信息
|
* @param clientInfo 请求的客户端的信息
|
* @return 登录的结果对象
|
* @throws VciBaseException 登录失败的时候抛出异常
|
*/
|
@Override
|
public LoginResultBO singleLogin(LoginUserDTO userDTO, RequestClientInfo clientInfo) throws VciBaseException {
|
return login(userDTO,clientInfo,false);
|
}
|
|
/**
|
* 退出系统
|
*
|
* @param userToken 用户的许可码
|
* @throws VciBaseException 删除会话信息出错的时候会抛出异常
|
*/
|
@Override
|
public void logout(String userToken) throws VciBaseException {
|
VciBaseUtil.alertNotNull(userToken,"用户的会话许可");
|
Map<String, Object> logoutpluginBeanMap =ApplicationContextProvider.getApplicationContext().getBeansWithAnnotation(VciLogoutPlugin.class);
|
if(!CollectionUtils.isEmpty(logoutpluginBeanMap)){
|
logoutpluginBeanMap.forEach((k,v) -> {
|
Method[] methods = v.getClass().getDeclaredMethods();
|
if(methods!=null&& methods.length>0){
|
for(Method method:methods){
|
if(method.isAnnotationPresent(VciLogoutBefore.class)){
|
try {
|
method.invoke(v,userToken);
|
} catch(Throwable e){
|
if(logger.isErrorEnabled()){
|
logger.error("调用退出之前的插件出错",e);
|
}
|
throw new VciBaseException("调用退出之前的插件出错,{0},{1}",new String[]{v.getClass().getName(),method.getName()},e);
|
}
|
}
|
}
|
}
|
});
|
}
|
sessionForLogin.logout(userToken);
|
if(!CollectionUtils.isEmpty(logoutpluginBeanMap)){
|
logoutpluginBeanMap.forEach((k,v) -> {
|
Method[] methods = v.getClass().getDeclaredMethods();
|
if(methods!=null&& methods.length>0){
|
for(Method method:methods){
|
if(method.isAnnotationPresent(VciLoginAfter.class)){
|
try {
|
method.invoke(v,userToken);
|
} catch(Throwable e){
|
if(logger.isErrorEnabled()){
|
logger.error("调用退出登录之后的插件出错",e);
|
}
|
throw new VciBaseException("调用退出登录之后插件出错,{0},{1}",new String[]{v.getClass().getName(),method.getName()},e);
|
}
|
}
|
}
|
}
|
});
|
}
|
}
|
|
|
|
/**
|
* 保存会话信息
|
* @param sessionInfo 会话信息
|
*/
|
private TokenVO saveSessionInfo(SessionInfo sessionInfo){
|
if(sessionForLogin == null){
|
throw new VciBaseException("没有配置会话存储的服务");
|
}
|
WebThreadLocalUtil.setCurrentUserSessionInfoInThread(sessionInfo);
|
return sessionForLogin.createToken(sessionInfo);
|
}
|
|
/**
|
* 拷贝请求的信息到会话信息中
|
* @param clientInfo 请求信息
|
* @param sessionInfo 会话信息
|
*/
|
private void copyRequest2SessionInfo(RequestClientInfo clientInfo, SessionInfo sessionInfo) {
|
sessionInfo.setIp(clientInfo.getIpaddress());
|
//ip的地址在controller里设置
|
sessionInfo.setOs(clientInfo.getOsversion());
|
sessionInfo.setBrowser(clientInfo.getBrowserversion());
|
sessionInfo.setSso(clientInfo.isSso());
|
sessionInfo.setSsoServiceName(clientInfo.getSsoSystemName());
|
}
|
|
/**
|
* 拷贝用户的信息到 会话信息
|
* @param user 用户对象
|
* @param sessionInfo 会话对象
|
* @param langCode 语言编码
|
*/
|
private void copyUser2SessionInfo(SmUserVO user, SessionInfo sessionInfo, String langCode){
|
sessionInfo.setUserOid(user.getOid());
|
sessionInfo.setUserId(user.getId());
|
sessionInfo.setUserName(user.getName());
|
sessionInfo.setUsertype(user.getUserType());
|
sessionInfo.setUsertypeText(user.getUserTypeText());
|
sessionInfo.setUserSecret(user.getSecretGrade()==null?"":(user.getSecretGrade()+ ""));
|
sessionInfo.setUserSecretText(user.getSecretGradeText());
|
sessionInfo.setSex(user.getSex());
|
sessionInfo.setSexText(user.getSexText());
|
//sessionInfo.setPhotoUrl(user.getPhoto());
|
sessionInfo.setLanguage(user.getLangCode());
|
if(StringUtils.isNotBlank(langCode)){
|
//传递了要显示的语言
|
sessionInfo.setLanguage(langCode);
|
}
|
sessionInfo.setPersonOid(user.getPkPerson());
|
sessionInfo.setPersonName(user.getPkPersonName());
|
sessionInfo.setDeptOid(user.getPkDepartment());
|
sessionInfo.setDeptName(user.getPkDepartmentName());
|
sessionInfo.setDutyOid(user.getPkDuty());
|
sessionInfo.setDutyName(user.getPkDutyName());
|
sessionInfo.setEmail(user.getEmail());
|
sessionInfo.setPhoneNo(user.getTel());
|
sessionInfo.setRtxNo(user.getRtxNo());
|
sessionInfo.setIMId(user.getIMNo());
|
sessionInfo.setPortalId(user.getId());
|
sessionInfo.setLastLoginTime(user.getLastLoginTime()!=null?user.getLastLoginTime().getTime(): VciDateUtil.getNowTime());
|
}
|
|
/**
|
* 更新用户的错误次数
|
* @param userOid 用户主键
|
* @param wrongCount 错误次数
|
*/
|
private void updateUserPwdWrongCount(String userOid,Integer wrongCount){
|
userQueryService.updateUserPwdWrongCount(userOid,wrongCount);
|
}
|
|
/**
|
* 添加用户到解锁队列中
|
* @param userId 用户的账号
|
* @param lockTime 锁定时间,单位是分
|
*/
|
public void addUserToUnLock(String userId,Integer lockTime){
|
//是因为被锁定,需要添加自动解锁
|
if(lockTime == null){
|
//防止数据出错,没有lockTime
|
lockTime = 30;
|
}
|
userQueryService.lockUser(userId);
|
unLockTaskManager.put(new SmUserUnLockTask(userQueryService,userId,(long)lockTime*60*1000));
|
}
|
|
/**
|
* 登录成功后更新用户信息
|
* @param userOid 用户主键
|
*/
|
private void updateUserForLoginSuccess(String userOid){
|
userQueryService.updateUserLoginTime(userOid);
|
}
|
|
/**
|
* 获取登录错误码
|
* @param chkRes 平台登录校验结果
|
* @Return java.lang.String
|
*/
|
public String getErrorCode(LoginResult chkRes){
|
String message = "";
|
switch(chkRes.state.value())
|
{
|
case 0:
|
return "";
|
case 1:
|
return LOGIN_SUCCESS;
|
case 10:
|
return USER_NOT_FOUND;
|
case 11:
|
return USER_PWD_NOT_EQUAL;
|
case 12:
|
return USER_IS_DISABLED;
|
case 13:
|
return USER_IS_LOCK;
|
case 14:
|
return PASSWORD_INIT;
|
case 15:
|
return PASSWORD_REMAIN_DAY;
|
case 16:
|
return PASSWORD_EXPIRE;
|
case 17:
|
return PASSWORD_POLICY_UPDATED;
|
case 20:
|
return SYSTEM_ERROR;
|
default:
|
message = SYSTEM_ERROR;
|
break;
|
}
|
return message;
|
}
|
}
|