package com.vci.web.service.impl;
|
|
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.lcstatuspck.FrameworkDataLCStatus;
|
import com.vci.frameworkcore.pagemodel.SmFunctionVO;
|
import com.vci.frameworkcore.pagemodel.SmPasswordStrategyVO;
|
import com.vci.frameworkcore.pagemodel.SmRoleVO;
|
import com.vci.frameworkcore.pagemodel.SmUserVO;
|
import com.vci.starter.web.annotation.bus.*;
|
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.util.ApplicationContextProvider;
|
import com.vci.starter.web.util.Md5;
|
import com.vci.starter.web.util.VciBaseUtil;
|
import com.vci.starter.web.util.VciDateUtil;
|
import com.vci.web.bo.LoginResultBO;
|
import com.vci.web.dto.LoginUserDTO;
|
import com.vci.frameworkcore.properties.VciSecurityManageProperties;
|
import com.vci.web.service.LoginServiceI;
|
import com.vci.web.util.BusAnnotationUtil;
|
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 java.lang.reflect.Method;
|
import java.text.MessageFormat;
|
import java.util.*;
|
import java.util.stream.Collectors;
|
|
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());
|
|
/**
|
* 会话处理
|
*/
|
@Autowired
|
private VciSessionForLoginI sessionForLogin;
|
|
/**
|
* 解锁任务
|
*/
|
@Autowired
|
private SmUserUnLockTaskManager unLockTaskManager;
|
|
/**
|
* 权限管理的相关配置
|
*/
|
@Autowired
|
private VciSecurityManageProperties securityManageProperties;
|
|
/**
|
* 用户查询服务,可以兼容老平台
|
*/
|
@Autowired()
|
private SmUserQueryServiceI userQueryService;
|
|
/**
|
* 角色的查询服务,可以兼容老平台
|
*/
|
@Autowired
|
private SmRoleQueryServiceI roleQueryService;
|
|
/**
|
* 权限的查询服务,可以兼容老平台
|
*/
|
@Autowired
|
private ISmFunctionQueryService functionQueryService;
|
|
/**
|
* 执行登录
|
* @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(), "登录密码");
|
// }
|
//登录之前调用插件
|
BusAnnotationUtil.callForAnnotation(VciLoginPlugin.class,VciLoginBefore.class,userDTO,clientInfo);
|
|
// String loginInfo = checkIsLogined(userDTO.getUserId());
|
// if (!userDTO.isForceLogin() && securityManageProperties.isUserOneLogin()) {
|
// //需要看看是否已经登录了
|
// if (StringUtils.isNotBlank(loginInfo)) {
|
// loginResult.setFailCode(USER_IS_LOGINED);
|
// loginResult.setFailMsg(loginInfo);
|
// return loginResult;
|
// }
|
// }
|
//2.获取用户的对象.这里需要兼容老平台和老pdm,老编码和老平台是一个表
|
// SmUserVO user = userQueryService.getUserByUserId(userDTO.getUserId().trim());
|
// if (user == null || StringUtils.isEmpty(user.getOid())) {
|
// loginResult.setFailCode(USER_NOT_FOUND);
|
// 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;
|
// }
|
// }
|
// if (user.getPwdWrongCount() == null) {
|
// user.setPwdWrongCount(0);
|
// }
|
// 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 (logger.isDebugEnabled()) {
|
// logger.debug("{}的密码正确", user.getId());
|
// }
|
// user.setLastLoginTime(new Date());
|
// user.setPwdWrongCount(0);
|
SmUserVO user = new SmUserVO();
|
user.setId("1");
|
user.setName("1");
|
user.setOid("1");
|
user.setUserType("1");
|
user.setUserTypeText("1");
|
user.setSecretGrade(1);
|
user.setSecretGradeText("1");
|
user.setSex("1");
|
user.setSexText("1");
|
user.setPkPerson("1");
|
user.setPkPersonName("1");
|
user.setPkDepartment("1");
|
user.setPkDepartmentName("1");
|
user.setPkDuty("1");
|
user.setPkDutyName("1");
|
user.setEmail("1");
|
user.setTel("1");
|
user.setRtxNo("1");
|
user.setIMNo("1");
|
|
|
|
|
SessionInfo sessionInfo = new SessionInfo();
|
//拷贝用户的新到session会话中
|
copyUser2SessionInfo(user, sessionInfo, userDTO.getLangCode());
|
//拷贝请求信息到session会话中
|
copyRequest2SessionInfo(clientInfo, sessionInfo);
|
//查询所有的角色
|
// 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());
|
// }
|
|
loginResult.setSuccess(true);
|
//检查是否该修改密码
|
// 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)}));
|
// }
|
// }
|
// }
|
// }
|
|
//原本想使用jwt来生成token,但是有以下问题
|
//1.jwt不能处理注销的问题
|
//2.jwt生成的token太长了
|
//3.因为本平台不是互联网系统,只需要解决分布式用户信息的获取和权限的校验即可。
|
//4.平台引用了redis和数据库来存储会话的信息,只需要保证根据token能获取到会话信息即可
|
//5.在服务启动的时候,将会话信息清除,在注销的时候将会话信息清除
|
//uuid在高并发的情况下会重复,但是传统软件并发很小,所以出现的重复的概率很小
|
|
sessionInfo.setToken(Md5.md5(VciBaseUtil.getPk() + "_" + user.getId()));
|
loginResult.setSessionInfo(sessionInfo);
|
// updateUserForLoginSuccess(user.getOid());
|
// if (StringUtils.isNotBlank(loginInfo) && userDTO.isForceLogin() && securityManageProperties.isUserOneLogin()) {
|
// //说明已经登录了,那应该取消原来的登录
|
// popUser(userDTO.getUserId());
|
// }
|
|
//添加到会话信息
|
// saveSessionInfo(sessionInfo);
|
|
//登录后执行
|
// BusAnnotationUtil.callForAnnotation(VciLoginPlugin.class,VciLoginAfter.class,userDTO,clientInfo,loginResult);
|
return loginResult;
|
}
|
|
|
/**
|
* 单点登录
|
*
|
* @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 userId 用户名
|
* @return 已经登录时,
|
*/
|
private String checkIsLogined(String userId) {
|
if(sessionForLogin == null){
|
throw new VciBaseException("没有配置会话存储的服务");
|
}
|
return sessionForLogin.checkIsLogined(userId);
|
}
|
|
/**
|
* 把以前的登录信息移除
|
* @param userId 用户名
|
*/
|
private void popUser(String userId){
|
if(sessionForLogin == null){
|
throw new VciBaseException("没有配置会话存储的服务");
|
}
|
sessionForLogin.popUser(userId);
|
}
|
|
/**
|
* 保存会话信息
|
* @param sessionInfo 会话信息
|
*/
|
private void saveSessionInfo(SessionInfo sessionInfo){
|
if(sessionForLogin == null){
|
throw new VciBaseException("没有配置会话存储的服务");
|
}
|
sessionForLogin.saveSessionInfo(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.setWorkNo(user.getWorkNo());
|
// sessionInfo.setWorkTypeOid(user.getPkWorkType());
|
// sessionInfo.setWorkTypeName(user.getPkWorkTypeText());
|
}
|
|
/**
|
* 更新用户的错误次数
|
* @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);
|
}
|
}
|