package com.tievd.cube.modules.system.service.impl; import cn.dev33.satoken.stp.SaTokenInfo; import cn.dev33.satoken.stp.StpUtil; import cn.hutool.core.math.Calculator; import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.SecureUtil; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.tievd.cube.application.config.properties.CaptchaConfigProperties; import com.tievd.cube.common.system.api.ISysBaseAPI; import com.tievd.cube.commons.base.Result; import com.tievd.cube.commons.constant.CacheConst; import com.tievd.cube.commons.exception.CubeAppException; import com.tievd.cube.commons.intf.ISmsSender; import com.tievd.cube.commons.utils.CommonUtil; import com.tievd.cube.commons.utils.SystemContextUtil; import com.tievd.cube.commons.utils.captcha.CaptchaGenerator; import com.tievd.cube.commons.utils.crypto.PasswordTransportUtil; import com.tievd.cube.commons.utils.crypto.PasswordUtil; import com.tievd.cube.commons.utils.spring.RedisUtil; import com.tievd.cube.modules.system.entity.SysDepart; import com.tievd.cube.modules.system.entity.SysUser; import com.tievd.cube.modules.system.mapper.SysDepartMapper; import com.tievd.cube.modules.system.mapper.SysLogMapper; import com.tievd.cube.modules.system.mapper.SysUserMapper; import com.tievd.cube.modules.system.model.SmsType; import com.tievd.cube.modules.system.model.api.response.LogInfoResponse; import com.tievd.cube.modules.system.model.api.response.LoginResponse; import com.tievd.cube.modules.system.model.api.response.VisitsInfo; import com.tievd.cube.modules.system.service.ILoginService; import com.tievd.cube.modules.system.service.ISysDictService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.List; @Slf4j @Service public class LoginServiceImpl implements ILoginService { @Autowired private SysDepartMapper sysDepartMapper; @Autowired private SysUserMapper sysUserMapper; @Autowired private SysLogMapper sysLogMapper; @Autowired private RedisUtil redisUtil; @Autowired private ISysBaseAPI sysBaseAPI; @Autowired private ISysDictService sysDictService; @Autowired private CaptchaConfigProperties captchaConfigProperties; @Autowired private CaptchaGenerator captchaGenerator; @Autowired(required = false) private ISmsSender smsSender; @Override public LoginResponse getUserInfo(SysUser sysUser) { String username = sysUser.getUsername(); // 获取用户部门信息 LoginResponse loginResponse = new LoginResponse(); List departs = sysDepartMapper.queryUserDeparts(sysUser.getId()); loginResponse.setDeparts(departs); if (departs.size() == 1) { SysDepart sysDepart = departs.get(0); sysUser.setOrgCode(sysDepart.getOrgCode()); sysUser.setOrgCodeTxt(sysDepart.getDepartName()); sysUserMapper.updateUserDepart(username, sysDepart.getOrgCode()); } // 生成token StpUtil.login(username); SaTokenInfo saTokenInfo = StpUtil.getTokenInfo(); loginResponse.setToken(saTokenInfo.getTokenValue()); loginResponse.setTokenTimeout(saTokenInfo.getTokenTimeout()); loginResponse.setUserInfo(sysUser); loginResponse.setUserRoles(sysBaseAPI.queryUserRoles(sysUser.getUsername())); loginResponse.setSysAllDictItems(sysDictService.queryAllDictItems()); // 登录日志 SystemContextUtil.log("登录成功,登录凭证:" + saTokenInfo.getTokenValue()); // 删除原有用户信息缓存 redisUtil.del(String.format("%s::%s", CacheConst.SYS_USERS_CACHE, username)); return loginResponse; } @Override public LoginResponse loginWithPassword(String username, String password, String captcha, String checkKey) { //AES CBC 解密 password = PasswordTransportUtil.getPlaintext(password); if (captchaConfigProperties.isEnable()) { if (StrUtil.isEmpty(captcha)) { throw new CubeAppException("请填写验证码!"); } String lowerCaseCaptcha = captcha.toLowerCase(); String realKey = SecureUtil.md5(lowerCaseCaptcha + checkKey); Object checkCode = redisUtil.get(realKey); //当进入登录页时,有一定几率出现验证码错误 #1714 if (checkCode == null || !String.valueOf(checkCode).equals(lowerCaseCaptcha)) { throw new CubeAppException("验证码错误!"); } } //1. 校验用户是否有效 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(SysUser::getUsername, username); SysUser sysUser = sysUserMapper.selectOne(queryWrapper); Result userState = sysBaseAPI.checkUserState(sysUser); if (!userState.isSuccess()) { throw new CubeAppException(userState.getMessage()); } //2. 校验用户名或密码是否正确 String userInputPassword = PasswordUtil.encrypt(username, password, sysUser.getSalt()); String userPassword = sysUser.getPassword(); if (!userPassword.equals(userInputPassword)) { throw new CubeAppException("用户名或密码错误!"); } return this.getUserInfo(sysUser); } @Override public LoginResponse loginWithCode(String phone, String code) { //校验用户有效性 SysUser sysUser = sysUserMapper.getUserByPhone(phone); Result userState = sysBaseAPI.checkUserState(sysUser); if (!userState.isSuccess()) { throw new CubeAppException(userState.getMessage()); } Object verificationCode = redisUtil.get(phone); if (!code.equals(verificationCode)) { throw new CubeAppException("手机验证码错误!"); } return this.getUserInfo(sysUser); } @Override public void logout() { // 删除用户的缓存信息(包括部门信息),例如sys:cache:user:: redisUtil.del(String.format("%s::%s", CacheConst.SYS_USERS_CACHE, StpUtil.getLoginIdAsString())); StpUtil.logout(); SystemContextUtil.log("登出成功,登录凭证:" + StpUtil.getTokenInfo().getTokenValue()); } @Override public LogInfoResponse visitsToday() { // 获取一天的开始和结束时间 Calendar calendar = new GregorianCalendar(); calendar.set(Calendar.HOUR_OF_DAY, 0); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); Date dayStart = calendar.getTime(); calendar.add(Calendar.DATE, 1); Date dayEnd = calendar.getTime(); // 获取系统访问记录 Long totalVisitCount = sysLogMapper.findTotalVisitCount(); Long todayVisitCount = sysLogMapper.findTodayVisitCount(dayStart, dayEnd); Long todayIp = sysLogMapper.findTodayIp(dayStart, dayEnd); return new LogInfoResponse(totalVisitCount, todayVisitCount, todayIp); } @Override public List visitsSevenDay() { Calendar calendar = new GregorianCalendar(); calendar.set(Calendar.HOUR_OF_DAY, 0); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); calendar.add(Calendar.DAY_OF_MONTH, 1); Date dayEnd = calendar.getTime(); calendar.add(Calendar.DAY_OF_MONTH, -7); Date dayStart = calendar.getTime(); String dbType = CommonUtil.getDatabaseType(); return sysLogMapper.findVisitCount(dayStart, dayEnd, dbType); } @Override public SysUser selectDepart(String orgCode) { String username = StpUtil.getLoginIdAsString(); // 重新选择部门时删除原有缓存 redisUtil.del(String.format("%s::%s", CacheConst.SYS_USERS_CACHE, username)); if (StrUtil.isNotEmpty(orgCode)) { sysUserMapper.updateUserDepart(username, orgCode); } SysUser sysUser = sysUserMapper.getUserByName(username); String departName = sysBaseAPI.translateDictFromTable("sys_depart", "depart_name", "org_code", orgCode); sysUser.setOrgCodeTxt(departName); return sysUser; } @Override public void sendSms(String phone, String mode) { String captcha = RandomUtil.randomNumbers(6); SmsType smsType = SmsType.SECURITY_TEMPLATE; switch (mode) { case "0": smsType = SmsType.LOGIN_TEMPLATE; break; case "1": SysUser sysUser = sysUserMapper.getUserByPhone(phone); if (sysUser != null) { throw new CubeAppException("手机号已经注册,请直接登录!"); } break; case "2": smsType = SmsType.FORGET_PASSWORD_TEMPLATE; break; } redisUtil.set(phone, captcha, 600); if (smsSender != null) { JSONObject params = JSONUtil.createObj(); params.set("code", captcha); smsSender.send(phone, smsType, params); } log.info("Send SMS template={} code={} phone={} !", smsType.name(), captcha, phone); } @Override public String randomImage(String key) { String base64 = captchaGenerator.generate(); String lowerCaseCode = captchaGenerator.getCode().toLowerCase(); if (captchaConfigProperties.isMath()) { int calculateResult = (int) Calculator.conversion(lowerCaseCode); lowerCaseCode = String.valueOf(calculateResult); } String realKey = SecureUtil.md5(lowerCaseCode + key); redisUtil.set(realKey, lowerCaseCode, 60 * 2); return base64; } @Override public void checkCaptcha(String captcha, String checkKey) { String lowerCaseCaptcha = captcha.toLowerCase(); String realKey = SecureUtil.md5(lowerCaseCaptcha + checkKey); Object checkCode = redisUtil.get(realKey); if (checkCode == null || !checkCode.equals(lowerCaseCaptcha)) { throw new CubeAppException("验证码错误!"); } } }