package pwc.taxtech.atms.service.impl; import org.apache.commons.lang3.BooleanUtils; import org.apache.ibatis.session.RowBounds; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.Assert; import org.springframework.util.StringUtils; import pwc.taxtech.atms.common.*; import pwc.taxtech.atms.common.message.UserMessage; import pwc.taxtech.atms.dao.UserHistoricalPasswordMapper; import pwc.taxtech.atms.dao.UserMapper; import pwc.taxtech.atms.dto.ForgetPasswordDto; import pwc.taxtech.atms.dto.LoginOutputDto; import pwc.taxtech.atms.dto.MailMto; import pwc.taxtech.atms.dto.OperationResultDto; import pwc.taxtech.atms.dto.UpdateLogParams; import pwc.taxtech.atms.dto.user.UserAndUserRoleSaveDto; import pwc.taxtech.atms.dto.user.UserPasswordDto; import pwc.taxtech.atms.entity.*; import pwc.taxtech.atms.entity.UserHistoricalPasswordExample.Criteria; import pwc.taxtech.atms.security.AtmsPasswordEncoder; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Objects; @Service public class UserAccountServiceImpl extends AbstractService { // TODO Move it to constants file private static final String MAIL_TEMPLATE_PATH = "mailTemplate/"; private static final Logger logger = LoggerFactory.getLogger(UserAccountServiceImpl.class); @Autowired private UserMapper userMapper; @Autowired private StringHelper stringHelper; @Autowired private UserHistoricalPasswordMapper userHistoricalPasswordMapper; @Autowired private UserServiceImpl userService; @Autowired private CommonServiceImpl commonService; @Autowired private AtmsPasswordEncoder atmsPasswordEncoder; @Autowired private AuthUserHelper authUserHelper; @Autowired private AtmsApiSettings atmsApiSettings; public OperationResultDto<LoginOutputDto> changeExternalUserPassword(UserPasswordDto userPasswordDto) { logger.debug("修改密码 Start"); final String userName = authUserHelper.getCurrentAuditor().get(); // find exist user User tempUser = userMapper.selectByUserNameIgnoreCase(userName); // verify old password OperationResultDto<LoginOutputDto> loginResult = userService.activeCheck(tempUser); if (loginResult.getResult() != null && loginResult.getResult()) { logger.debug("result is true after activeCheck"); loginResult = userService.externalUserLogin(tempUser, userName, userPasswordDto.getOldPassword()); } else { logger.debug("result is false after activeCheck"); } if (loginResult.getResult() != null && loginResult.getResult()) { logger.debug("result is true after externalUserLogin"); if (tempUser.getAttemptTimes() != null && tempUser.getAttemptTimes() != 0) { logger.debug("call method resetAttemptTimes"); resetAttemptTimes(tempUser); } } else { logger.debug("result is false after externalUserLogin"); if (loginResult.getData() != null && CheckState.WrongPassword.value().equals(loginResult.getData().getCheckState())) { logger.debug("ready to call dealWithWrongPassword"); dealWithWrongPassword(tempUser); } if (loginResult.getData() != null && loginResult.getData().getCheckState() != null) { String msg = CheckState.int2str(loginResult.getData().getCheckState()); logger.debug("set setResultMsg to:{}", msg); loginResult.setResultMsg(msg); return loginResult; } } String newEncodedPassword = atmsPasswordEncoder.encode(userPasswordDto.getNewPassword()); // check history if (checkHistoricalPassword(tempUser.getId(), newEncodedPassword)) { logger.debug("历史密码验证失败:密码已被使用"); loginResult.setResult(false); loginResult.setResultMsg(UserMessage.UsedPassword); } else { logger.debug("历史密码验证通过"); } if (loginResult.getResult() != null && loginResult.getResult()) { // set new password setNewPassword(tempUser, newEncodedPassword); logger.debug("设置新密码成功"); } else { logger.debug("loginResult.result is false"); } return loginResult; } private void setNewPassword(User tempUser, String newEncodedPassword) { // 因为C#的创建UserHistoricalPassword的代码被注释了,所以跳过创建UserHistoricalPassword tempUser.setPassword(newEncodedPassword); User userTarget = new User(); userTarget.setPassword(tempUser.getPassword()); userTarget.setUpdateTime(new Date()); userTarget.setId(tempUser.getId()); int resultCount = userMapper.updateByPrimaryKeySelective(userTarget); Assert.state(resultCount > 0, "Zero update count"); } private boolean checkHistoricalPassword(String id, String newEncodedPassword) { UserHistoricalPasswordExample example = new UserHistoricalPasswordExample(); example.setOrderByClause("UpdateTime desc"); Criteria criteria = example.createCriteria(); // criteria.andPasswordEqualTo(newEncodedPassword); criteria.andIdEqualTo(id); RowBounds rowBounds = new RowBounds(0, CommonConstants.MaxSamePasswordNumber); List<UserHistoricalPassword> list = userHistoricalPasswordMapper.selectByExampleWithRowbounds(example, rowBounds); boolean containsOldPassword = false; for (UserHistoricalPassword item : list) { if (item.getPassword() != null && item.getPassword().equals(newEncodedPassword)) { containsOldPassword = true; break; } } return containsOldPassword; } public void resetAttemptTimes(User tempUser) { User userTarget = new User(); userTarget.setAttemptTimes(0); userTarget.setId(tempUser.getId()); userMapper.updateByPrimaryKeySelective(userTarget); } public void dealWithWrongPassword(User tempUser) { User userTarget = new User(); userTarget.setId(tempUser.getId()); tempUser.setAttemptTimes(tempUser.getAttemptTimes() == null ? 0 : tempUser.getAttemptTimes() + 1); userTarget.setAttemptTimes(tempUser.getAttemptTimes()); logger.debug("print attemptimes [{}]", tempUser.getAttemptTimes()); if (tempUser.getAttemptTimes() >= CommonConstants.MaxAttemptTimes) { logger.warn("Lock user [{}] due to attemptimes is [{}]", tempUser.getUserName(), tempUser.getAttemptTimes()); tempUser.setStatus(UserStatus.Locked.value()); userTarget.setStatus(tempUser.getStatus()); tempUser.setLockedTime(new Date()); userTarget.setLockedTime(tempUser.getLockedTime()); } else { logger.debug("update user [{}] attemptTimes to [{}]", tempUser.getUserName(), tempUser.getAttemptTimes()); } userMapper.updateByPrimaryKeySelective(userTarget); } public OperationResultDto<Object> forgetPassword(final String mail) { OperationResultDto<ForgetPasswordDto> result = forgetPasswordForUser(mail); if (result == null || result.getResult() == null || !result.getResult()) { logger.info("the result is false by calling forgetPasswordForUser"); // 如果失败,直接返回,跳过发邮件 return new OperationResultDto<>(true); } logger.info("the result is true by calling forgetPasswordForUser"); ForgetPasswordDto forgetPasswordDto = result.getData(); Assert.notNull(forgetPasswordDto, "Null data"); // 发邮件 String path = MAIL_TEMPLATE_PATH + "WebAdminResetPasswordLetter.html"; String text = CommonUtils.readClasspathFileToString(path); text = text.replaceAll("\\{Password\\}", forgetPasswordDto.getNewPassword()); text = text.replaceAll("\\{\\[Env\\]link\\}", atmsApiSettings.getWebUrl()); text = text.replaceAll("\\{UserName\\}", forgetPasswordDto.getUserName()); String subject = readHtmlTitle(text); MailMto mailmto = new MailMto(); mailmto.setContent(text); mailmto.setTo(mail); mailmto.setSubject(subject); commonService.sendMail(mailmto); return new OperationResultDto<>(true); } public String readHtmlTitle(String text) { try { String beginTag = "<title>"; String endTag = "</title>"; int beginIndex = text.indexOf(beginTag); int endIndex = text.indexOf(endTag); // String subject = text.substring(beginTag.length() + beginIndex, endIndex - // beginIndex - endTag.length()); String subject = text.substring(beginTag.length() + beginIndex, endIndex); subject = subject.trim(); return subject; } catch (Exception e) { logger.error("Cannot get subject:" + e, e); return "NA"; } } private OperationResultDto<ForgetPasswordDto> forgetPasswordForUser(String mail) { if (!StringUtils.hasText(mail) || !mail.contains("@")) { return new OperationResultDto<>(false); } User tempUser = userMapper.selectByUserNameIgnoreCase(mail); if (tempUser == null) { return new OperationResultDto<>(false); } final String newPassword = stringHelper.generateRandomPassword(); String encodedPassword = atmsPasswordEncoder.encode(newPassword); tempUser.setPasswordUpdateTime(new Date()); tempUser.setStatus(UserStatus.InActive.value()); tempUser.setPassword(encodedPassword); userMapper.updateByPrimaryKey(tempUser); ForgetPasswordDto forgetPasswordDto = new ForgetPasswordDto(); forgetPasswordDto.setNewPassword(newPassword); // 因为C#代码没有设置changeResult, 所以这里不设置changeResult forgetPasswordDto.setUserName(tempUser.getUserName()); return new OperationResultDto<>(true, null, forgetPasswordDto); } public OperationResultDto<User> addNewUser(UserAndUserRoleSaveDto userAndUserRoleSaveDto) { OperationResultDto<User> user = addUser(userAndUserRoleSaveDto); //todo send mail // if (BooleanUtils.isTrue(user.getResult())) { // MailMto mailMto = new MailMto(); // String path = MAIL_TEMPLATE_PATH + "WebAdminWelcomeLetter.html"; // String content = CommonUtils.readClasspathFileToString(path); // content = content.replaceAll("\\{Password\\}", user.getResultMsg()); // content = content.replaceAll("\\{\\[Env\\]link\\}", atmsApiSettings.getWebUrl()); // content = content.replaceAll("\\{UserName\\}", user.getData().getUserName()); // mailMto.setContent(content); // // Get Subject Avoid Multi-language // String beginTag = "<title>"; // int beginIndex = content.indexOf(beginTag); // int endIndex = content.indexOf("</title>"); // String subject = content.substring(beginIndex + beginTag.length(), endIndex); // mailMto.setSubject(subject); // mailMto.setTo(user.getData().getEmail()); // commonService.sendMail(mailMto); // } return user; } public OperationResultDto<User> addUser(UserAndUserRoleSaveDto userAndUserRoleSaveDto) { String userName = authUserHelper.getCurrentAuditor().get(); OperationResultDto<User> operationResultDto = new OperationResultDto<>(); OperationResultDto<User> result = userService.checkUserExist(userAndUserRoleSaveDto.getUserName(), CommonConstants.EMPTY_UUID); if (result != null && BooleanUtils.isFalse(result.getResult())) { return result; } result = userService.checkEmailExist(userAndUserRoleSaveDto.getEmail(), CommonConstants.EMPTY_UUID); if (result != null && BooleanUtils.isFalse(result.getResult())) { return result; } if (BooleanUtils.isTrue(userAndUserRoleSaveDto.getIsAdmin())) { User operateUser = userMapper.selectByUserNameIgnoreCase(userName); // cs代码逻辑微调, 如果正在执行操作的用户不是admin(isAdmin:0)或者没有设置admin权限(isAdmin:null), 则不执行操作 if (operateUser != null && !BooleanUtils.isTrue(operateUser.getIsAdmin())) { operationResultDto.setResult(false); operationResultDto.setResultMsg(UserMessage.HasNoPermission); } } User user = CommonUtils.copyProperties(userAndUserRoleSaveDto, new User()); // 根据cs代码的mapper方法初始化user的isAdmin值 user.setIsAdmin(BooleanUtils.isTrue(userAndUserRoleSaveDto.getIsAdmin())); if(userAndUserRoleSaveDto.getRoleNames().contains("超级管理员")){ user.setIsSuperAdmin(true); } user.setId(CommonUtils.getUUID()); user.setStatus(UserStatus.Active.value()); // loginType:{1:AD认证,2:用户名密码登录验证,3:外部用户登录,使用Email和密码登录,因为目前没有选择登录类型,所以直接设置为3,全部使用密码验证,以后根据需求变更} user.setLoginType(UserLoginType.ExternalUser); List<UserRole> userRoleList = new ArrayList<>(); // new password // String newPwd = stringHelper.generateRandomPassword(); String newPwd = "12345678";//todo 没有发邮件,先默认这个 user.setPassword(atmsPasswordEncoder.encode(newPwd)); user.setCreateTime( userAndUserRoleSaveDto.getCreateTime() == null ? new Date() : userAndUserRoleSaveDto.getCreateTime()); user.setUpdateTime( userAndUserRoleSaveDto.getUpdateTime() == null ? new Date() : userAndUserRoleSaveDto.getUpdateTime()); user.setAttemptTimes( userAndUserRoleSaveDto.getAttemptTimes() == null ? 0 : userAndUserRoleSaveDto.getAttemptTimes()); user.setIsSuperAdmin(false); logger.debug("Start to insert new user [ {} ]", user.getId()); userMapper.insert(user); List<String> arrRoles = userAndUserRoleSaveDto.getRoleIds(); List<Role> roleQuery = roleMapper.selectByExample(new RoleExample()); // List<Role> roleQuery = roleData.selectByServiceTypeId("All"); if (arrRoles != null && !arrRoles.isEmpty()) { for (String role : arrRoles) { UserRole userRole = new UserRole(); userRole.setId(CommonUtils.getUUID()); userRole.setUserId(user.getId()); userRole.setRoleId(role); userRole.setServiceTypeId(roleQuery.stream().filter(p -> Objects.equals(p.getId(), role)).findFirst() .orElse(new Role()).getServiceTypeId()); userRoleList.add(userRole); logger.debug("Start to insert user role [ {} ]", userRole.getId()); userRoleMapper.insertSelective(userRole); } } // 默认添加机构可访问权限 UserOrganization userOrganization = new UserOrganization(); userOrganization.setUserId(user.getId()); userOrganization.setHasOriginalRole(CommonConstants.HasOriginalRole); userOrganization.setOrganizationId(user.getOrganizationId()); userOrganization.setId(CommonUtils.getUUID()); userOrganization.setIsAccessible(CommonConstants.IsAccessible); logger.debug("Start to insert user organization [ {} ]", userOrganization.getId()); userOrganizationMapper.insert(userOrganization); operationLogService.addOrDeleteDataAddLog(generateUpdateLogParams(OperationModule.User.value(), user.getUserName(), user.getUserName(), OperationAction.AddNewUser.value())); List<UpdateLogParams> userRoleLogs = new ArrayList<>(); for (UserRole userRole : userRoleList) { Role role = roleQuery.stream().filter(sa -> Objects.equals(sa.getId(), userRole.getRoleId())).findFirst() .orElse(null); userRoleLogs.add(generateUpdateLogParams(OperationModule.UserRole.value(), role == null ? "" : role.getName(), user.getUserName(), OperationAction.AddNewPermission.value())); } operationLogService.addOrDeleteDataAddLog(userRoleLogs); operationResultDto.setResult(true); operationResultDto.setData(user); operationResultDto.setResultMsg(newPwd); return operationResultDto; } private UpdateLogParams generateUpdateLogParams(Integer module, String operationContent, String operateObject, Integer action) { UpdateLogParams updateLogParams = new UpdateLogParams(); updateLogParams.setOperationModule(module); updateLogParams.setOperationContent(operationContent); updateLogParams.setOperationObject(operateObject); updateLogParams.setOperationAction(action); updateLogParams.setOperateLogType(OperateLogType.OperationLogUser.value()); return updateLogParams; } }