Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/service/impl/LoginServiceImpl.java
@@ -1,8 +1,6 @@
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;
@@ -10,11 +8,13 @@
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.SmPwdStrategyQueryServiceI;
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.lcstatuspck.FrameworkDataLCStatus;
import com.vci.pagemodel.SmFunctionVO;
import com.vci.pagemodel.SmPasswordStrategyVO;
import com.vci.pagemodel.SmUserVO;
import com.vci.frameworkcore.properties.VciSecurityManageProperties;
import com.vci.starter.web.annotation.bus.VciLoginAfter;
import com.vci.starter.web.annotation.bus.VciLogoutBefore;
@@ -25,27 +25,28 @@
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.bo.LoginResultBO;
import com.vci.constant.CacheNameConstant;
import com.vci.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.Func;
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 java.text.MessageFormat;
import java.util.*;
import java.util.stream.Collectors;
import static com.vci.frameworkcore.constant.FrameWorkBusLangCodeConstant.*;
import static com.vci.constant.FrameWorkBusLangCodeConstant.*;
/**
 * 登录的服务
@@ -85,16 +86,28 @@
    private SmUserQueryServiceI userQueryService;
    /**
     * 角色的查询服务,可以兼容老平台
     * 密码策略查询服务
     */
    @Resource
    private SmRoleQueryServiceI roleQueryService;
    private SmPwdStrategyQueryServiceI pwdStrategyQueryService;
    /**
     * 功能菜单的查询服务
     */
    @Resource
    private ISmFunctionQueryService functionQueryService;
    /**
     * 角色的查询服务,可以兼容老平台
     */
    //@Resource
    //private SmRoleQueryServiceI roleQueryService;
    /**
     * 权限的查询服务,可以兼容老平台
     */
    @Resource
    private ISmFunctionQueryService functionQueryService;
    //@Resource
    //private ISmFunctionQueryService functionQueryService;
    /**
     * redis服务
@@ -121,7 +134,7 @@
     * @throws VciBaseException 登录发生异常的时候出现了错误
     */
    @Override
    public LoginResultBO login(LoginUserDTO userDTO, RequestClientInfo clientInfo) throws VciBaseException {
    public LoginResultBO login(LoginUserDTO userDTO, RequestClientInfo clientInfo) throws PLException {
        return login(userDTO,clientInfo,true);
    }
@@ -133,16 +146,16 @@
     * @return 执行结果
     * @throws VciBaseException 参数错误,用户不能登录等会抛出异常
     */
    private LoginResultBO login(LoginUserDTO userDTO, RequestClientInfo clientInfo, boolean checkPassword) throws VciBaseException {
    private LoginResultBO login(LoginUserDTO userDTO, RequestClientInfo clientInfo, boolean checkPassword/*单点登录不需要校验密码*/) throws VciBaseException, PLException {
        LoginResultBO loginResult = new LoginResultBO();
        loginResult.setSuccess(false);
        //1.判断用户的基本信息
        VciBaseUtil.alertNotNull(userDTO, "登录信息", userDTO.getUserId(), "用户账号");
        if (checkPassword) {
            VciBaseUtil.alertNotNull(userDTO.getPassword(), "登录密码");
        }
        //需要看看是否已经登录了
        //2、判断单设备登录,是否已经登录了
        String userIdTokenKey = CacheNameConstant.cacheKey(CacheNameConstant.USERID_TOKEN_KEY, userDTO.getUserId().trim());
        if(redisService.hasKey(userIdTokenKey) && !userDTO.isForceLogin() && securityManageProperties.isUserOneLogin()){
            loginResult.setFailCode(USER_IS_LOGINED);
@@ -156,7 +169,151 @@
            redisService.deleteObject(userIdTokenKey);
        }
        //2.获取用户的对象.
        //3.获取用户的对象(对象中包含角色部门还有密码策略信息(当前用户没设置密码策略就是取的默认密码策略))
        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;
        }
        //4、判断密码是否正确(平台的checkLogin方法好像有对密码进行比对的方法)
        /*if (checkPassword) {
            boolean passwordIsEqual = userQueryService.checkPasswordEqual(userDTO.getPassword(), user.getOid());
            if (!passwordIsEqual) {
                if (logger.isDebugEnabled()) {
                    logger.debug("{}密码不正确", user.getId());
                }
            }
        }*/
        //5、调用平台登录接口,进行登录
        MachineInfo machine = getMachieInfo(clientInfo);
        machine.country = clientInfo.getCountry();
        machine.language = clientInfo.getLanguage();
        machine.osUser = clientInfo.getOsUser();
        machine.machine = clientInfo.getMachine();
        String token = null;
        try {
            /*ThreeDES des = new ThreeDES();// 实例化一个对�?
            des.getKey("daliantan0v0");// 生成密匙
            String encPassword = des.getDesString(userDTO.getPassword());*/
            LoginResult chkRes = platformClientUtil.getFrameworkService().checkLogin(userDTO.getUserId(),userDTO.getPassword(), machine);
            loginResult.setFailCode(getErrorCode(chkRes));
            //loginResult.setFailMsgArray(new String[]{userDTO.getUserId(), String.valueOf(chkRes.auxInfo)});
            loginResult.setFailMsgArray(new String[]{String.valueOf(chkRes.auxInfo)});
            //根据不同状态处理平台返回的信息
            if(chkRes.state.equals(LoginState.Error) || chkRes.state.equals(LoginState.Locked) || chkRes.state.equals(LoginState.Freeze)){
                return loginResult;
            }
            //关于密码策略相关的返回信息处理
            if(chkRes.state.equals(LoginState.InitialPW)){
                loginResult.setMustChangePassword(true);
                loginResult.setPasswordInfo("您的密码是管理员初始的密码,需要修改密码才能进行其它操作!");
                return loginResult;
            }else if(chkRes.state.equals(LoginState.PWExpired)){
                //需要立即修改密码
                loginResult.setMustChangePassword(true);
                loginResult.setPasswordInfo("您的密码已经过期,请进行修改!");
                return loginResult;
            }else if(chkRes.state.equals(LoginState.PWPolicyUpdated)){
                //策略修改,直接返回限制用户后续操作
                loginResult.setMustChangePassword(true);
                loginResult.setPasswordInfo("您的密码策略已经修改,需要修改密码才能进行其它操作!");
                return loginResult;
            }else if(chkRes.state.equals(LoginState.PWWillExpire)){
                loginResult.setPasswordInfo(String.format("您的密码有效期还有%s天,请注意修改!",chkRes.auxInfo));
            }
            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;
        }
        //6、登录成功之后需要处理的逻辑
        user.setLastLoginTime(new Date());//最后登录时间
        user.setPwdWrongCount(0);//密码错误次数清0
        //处理用户登录成功的session
        SessionInfo sessionInfo = new SessionInfo();
        sessionInfo.setToken(token);
        //初始化平台的token
        sessionForLogin.initInvocationInfo(sessionInfo);
        //拷贝用户到新的session会话中
        copyUser2SessionInfo(user, sessionInfo, userDTO.getLangCode());
        //拷贝请求信息到session会话中
        copyRequest2SessionInfo(clientInfo, sessionInfo);
        //查看了平台的登录方法其实是有处理部门角色等相关信息的但是不知道为什么无法获取到
        //部门信息处理
        sessionInfo.setDeptOid(user.getPkDepartment());
        sessionInfo.setDeptName(user.getPkDepartmentName());
        sessionInfo.setDeptNum(user.getPkDepartmentNum());
        //角色信息处理
        String roleOids = user.getPkPerson();
        String roleNames = user.getPkPersonName();
        HashMap<String, String> roleOidNameMap = new HashMap<>();
        if(Func.isNotBlank(roleOids) && Func.isNotBlank(roleOids)){
            String[] oids = roleOids.split(",");
            String[] names = roleNames.split(",");
            for (int i = 0; i < oids.length; i++) {
                roleOidNameMap.put(oids[i],names[i]);
            }
        }
        sessionInfo.setRolesName(roleOidNameMap);
        //查询所有的权限
        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;
    }
    /**
     * 登录_废弃方法,主要用来备份
     * @param userDTO 用户的数据传输对象
     * @param clientInfo 客户端的信息
     * @param checkPassword 是否校验密码
     * @return 执行结果
     * @throws VciBaseException 参数错误,用户不能登录等会抛出异常
     */
    private LoginResultBO login_old(LoginUserDTO userDTO, RequestClientInfo clientInfo, boolean checkPassword/*单点登录不需要校验密码*/) throws VciBaseException, PLException {
        LoginResultBO loginResult = new LoginResultBO();
        loginResult.setSuccess(false);
        //1.判断用户的基本信息
        VciBaseUtil.alertNotNull(userDTO, "登录信息", userDTO.getUserId(), "用户账号");
        if (checkPassword) {
            VciBaseUtil.alertNotNull(userDTO.getPassword(), "登录密码");
        }
        //2、判断单设备登录,是否已经登录了
        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);
        }
        //3.获取用户的对象(对象中包含角色部门还有密码策略信息)
        SmUserVO user = getUserByUserId(userDTO.getUserId().trim());
        if (user == null || StringUtils.isBlank(user.getOid())) {
            loginResult.setFailCode(USER_NOT_FOUND);
@@ -180,7 +337,6 @@
        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);
@@ -202,9 +358,7 @@
        }
        //如果用户已经被停用和锁定,不能登录
        //如果用户的失效日期已经超过了当前时间,不能登录
        //只有新平台的用户才判断失效
        /**if (FrameworkDataLCStatus.DISABLED.getValue().equals(user.getLcStatus())) {
        if (FrameworkDataLCStatus.DISABLED.getValue().equals(user.getLcStatus())) {
            loginResult.setFailCode(USER_IS_DISABLED);
            loginResult.setFailMsgArray(new String[]{userDTO.getUserId()});
            return loginResult;
@@ -214,7 +368,10 @@
            loginResult.setFailMsgArray(new String[]{userDTO.getUserId()});
            return loginResult;
        }
        if (user.getDisabledate() != null) {
        //如果用户的失效日期已经超过了当前时间,不能登录
        //只有新平台的用户才判断失效
        /*if (user.getDisabledate() != null) {
            //2021版本才有这个属性的值,当前这个没有这个值
            Date disableDate = VciDateUtil.addOrSubDate(user.getDisabledate(), Calendar.DATE, 1);
            if (disableDate != null && disableDate.getTime() < System.currentTimeMillis()) {
@@ -222,45 +379,43 @@
                loginResult.setFailMsgArray(new String[]{userDTO.getUserId()});
                return loginResult;
            }
        }
        SmPasswordStrategyVO passwordStrategyVO = userQueryService.getPasswordStrategyVOByUserOid(user.getOid());
        }*/
        //当前用户没有配置就查询默认的密码策略
        SmPasswordStrategyVO passwordStrategyVO = pwdStrategyQueryService.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;
                }
            //前端需要先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);
@@ -272,7 +427,7 @@
            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());
@@ -289,7 +444,7 @@
                    }
                }
            }
        }*/
        }
        //说明密码正确的
        if (logger.isDebugEnabled()) {
@@ -320,21 +475,21 @@
        }
        /** //查询所有的角色
        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());
        }*/
         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);
@@ -362,7 +517,6 @@
        return userQueryService.getUserByUserId(userId);
    }
    /**
     * 单点登录
     *
@@ -372,7 +526,7 @@
     * @throws VciBaseException 登录失败的时候抛出异常
     */
    @Override
    public LoginResultBO singleLogin(LoginUserDTO userDTO, RequestClientInfo clientInfo) throws VciBaseException {
    public LoginResultBO singleLogin(LoginUserDTO userDTO, RequestClientInfo clientInfo) throws PLException {
        return login(userDTO,clientInfo,false);
    }
@@ -426,8 +580,6 @@
            });
        }
    }
    /**
     * 保存会话信息
@@ -533,7 +685,7 @@
        switch(chkRes.state.value())
        {
            case 0:
                return "";
                return UNKNOWN;
            case 1:
                return LOGIN_SUCCESS;
            case 10: