干燥机配套车间生产管理系统/云平台服务端
bsw215583320
2024-04-16 c2fccb01b972176dc3da5a497b5e904025e9e98d
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/LoginController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,734 @@
package org.jeecg.modules.system.controller;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.exceptions.ClientException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CacheConstant;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.SymbolConstant;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.*;
import org.jeecg.common.util.encryption.EncryptedString;
import org.jeecg.config.JeecgBaseConfig;
import org.jeecg.modules.base.service.BaseCommonService;
import org.jeecg.modules.system.entity.SysDepart;
import org.jeecg.modules.system.entity.SysRoleIndex;
import org.jeecg.modules.system.entity.SysTenant;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.model.SysLoginModel;
import org.jeecg.modules.system.service.*;
import org.jeecg.modules.system.service.impl.SysBaseApiImpl;
import org.jeecg.modules.system.util.RandImageUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
/**
 * @Author scott
 * @since 2018-12-17
 */
@RestController
@RequestMapping("/sys")
@Api(tags="用户登录")
@Slf4j
public class LoginController {
   @Autowired
   private ISysUserService sysUserService;
   @Autowired
   private ISysPermissionService sysPermissionService;
   @Autowired
   private SysBaseApiImpl sysBaseApi;
   @Autowired
   private ISysLogService logService;
   @Autowired
    private RedisUtil redisUtil;
   @Autowired
    private ISysDepartService sysDepartService;
   @Autowired
   private ISysTenantService sysTenantService;
   @Autowired
    private ISysDictService sysDictService;
   @Resource
   private BaseCommonService baseCommonService;
   @Autowired
   private JeecgBaseConfig jeecgBaseConfig;
   private final String BASE_CHECK_CODES = "qwertyuiplkjhgfdsazxcvbnmQWERTYUPLKJHGFDSAZXCVBNM1234567890";
   @ApiOperation("登录接口")
   @RequestMapping(value = "/login", method = RequestMethod.POST)
   public Result<JSONObject> login(@RequestBody SysLoginModel sysLoginModel){
      Result<JSONObject> result = new Result<JSONObject>();
      String username = sysLoginModel.getUsername();
      String password = sysLoginModel.getPassword();
      //update-begin-author:taoyan date:2022-11-7 for: issues/4109 å¹³å°ç”¨æˆ·ç™»å½•失败锁定用户
      if(isLoginFailOvertimes(username)){
         return result.error500("该用户登录失败次数过多,请于10分钟后再次登录!");
      }
      //update-end-author:taoyan date:2022-11-7 for: issues/4109 å¹³å°ç”¨æˆ·ç™»å½•失败锁定用户
      //update-begin--Author:scott  Date:20190805 for:暂时注释掉密码加密逻辑,有点问题
      //前端密码加密,后端进行密码解密
      //password = AesEncryptUtil.desEncrypt(sysLoginModel.getPassword().replaceAll("%2B", "\\+")).trim();//密码解密
      //update-begin--Author:scott  Date:20190805 for:暂时注释掉密码加密逻辑,有点问题
      //update-begin-author:taoyan date:20190828 for:校验验证码
//        String captcha = sysLoginModel.getCaptcha();
//        if(captcha==null){
//            result.error500("验证码无效");
//            return result;
//        }
//        String lowerCaseCaptcha = captcha.toLowerCase();
        //update-begin-author:taoyan date:2022-9-13 for: VUEN-2245 ã€æ¼æ´žã€‘发现新漏洞待处理20220906
      // åŠ å…¥å¯†é’¥ä½œä¸ºæ··æ·†ï¼Œé¿å…ç®€å•çš„æ‹¼æŽ¥ï¼Œè¢«å¤–éƒ¨åˆ©ç”¨ï¼Œç”¨æˆ·è‡ªå®šä¹‰è¯¥å¯†é’¥å³å¯
        String origin = sysLoginModel.getCheckKey()+jeecgBaseConfig.getSignatureSecret();
      String realKey = Md5Util.md5Encode(origin, "utf-8");
      //update-end-author:taoyan date:2022-9-13 for: VUEN-2245 ã€æ¼æ´žã€‘发现新漏洞待处理20220906
      Object checkCode = redisUtil.get(realKey);
      //当进入登录页时,有一定几率出现验证码错误 #1714
//      if(checkCode==null || !checkCode.toString().equals(lowerCaseCaptcha)) {
//            log.warn("验证码错误,key= {} , Ui checkCode= {}, Redis checkCode = {}", sysLoginModel.getCheckKey(), lowerCaseCaptcha, checkCode);
//         result.error500("验证码错误");
//         // æ”¹æˆç‰¹æ®Šçš„code ä¾¿äºŽå‰ç«¯åˆ¤æ–­
//         result.setCode(HttpStatus.PRECONDITION_FAILED.value());
//         return result;
//      }
      //update-end-author:taoyan date:20190828 for:校验验证码
      //1. æ ¡éªŒç”¨æˆ·æ˜¯å¦æœ‰æ•ˆ
      //update-begin-author:wangshuai date:20200601 for: ç™»å½•代码验证用户是否注销bug,if条件永远为false
      LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
      queryWrapper.eq(SysUser::getUsername,username);
      SysUser sysUser = sysUserService.getOne(queryWrapper);
      //update-end-author:wangshuai date:20200601 for: ç™»å½•代码验证用户是否注销bug,if条件永远为false
      result = sysUserService.checkUserIsEffective(sysUser);
      if(!result.isSuccess()) {
         return result;
      }
      //2. æ ¡éªŒç”¨æˆ·åæˆ–密码是否正确
      String userpassword = PasswordUtil.encrypt(username, password, sysUser.getSalt());
      String syspassword = sysUser.getPassword();
      if (!syspassword.equals(userpassword)) {
         //update-begin-author:taoyan date:2022-11-7 for: issues/4109 å¹³å°ç”¨æˆ·ç™»å½•失败锁定用户
         addLoginFailOvertimes(username);
         //update-end-author:taoyan date:2022-11-7 for: issues/4109 å¹³å°ç”¨æˆ·ç™»å½•失败锁定用户
         result.error500("用户名或密码错误");
         return result;
      }
      //用户登录信息
      userInfo(sysUser, result);
      //update-begin--Author:liusq  Date:20210126  for:登录成功,删除redis中的验证码
      redisUtil.del(realKey);
      //update-begin--Author:liusq  Date:20210126  for:登录成功,删除redis中的验证码
      redisUtil.del(CommonConstant.LOGIN_FAIL + username);
      LoginUser loginUser = new LoginUser();
      BeanUtils.copyProperties(sysUser, loginUser);
      baseCommonService.addLog("用户名: " + username + ",登录成功!", CommonConstant.LOG_TYPE_1, null,loginUser);
        //update-end--Author:wangshuai  Date:20200714  for:登录日志没有记录人员
      return result;
   }
   /**
    * ã€vue3专用】获取用户信息
    */
   @GetMapping("/user/getUserInfo")
   public Result<JSONObject> getUserInfo(HttpServletRequest request){
      Result<JSONObject> result = new Result<JSONObject>();
      String  username = JwtUtil.getUserNameByToken(request);
      if(oConvertUtils.isNotEmpty(username)) {
         // æ ¹æ®ç”¨æˆ·åæŸ¥è¯¢ç”¨æˆ·ä¿¡æ¯
         SysUser sysUser = sysUserService.getUserByName(username);
         JSONObject obj=new JSONObject();
         //update-begin---author:scott ---date:2022-06-20  for:vue3前端,支持自定义首页-----------
         String version = request.getHeader(CommonConstant.VERSION);
         //update-begin---author:liusq ---date:2022-06-29  for:接口返回值修改,同步修改这里的判断逻辑-----------
         SysRoleIndex roleIndex = sysUserService.getDynamicIndexByUserRole(username, version);
         if (oConvertUtils.isNotEmpty(version) && roleIndex != null && oConvertUtils.isNotEmpty(roleIndex.getUrl())) {
            String homePath = roleIndex.getUrl();
            if (!homePath.startsWith(SymbolConstant.SINGLE_SLASH)) {
               homePath = SymbolConstant.SINGLE_SLASH + homePath;
            }
            sysUser.setHomePath(homePath);
         }
         //update-begin---author:liusq ---date:2022-06-29  for:接口返回值修改,同步修改这里的判断逻辑-----------
         //update-end---author:scott ---date::2022-06-20  for:vue3前端,支持自定义首页--------------
         obj.put("userInfo",sysUser);
         obj.put("sysAllDictItems", sysDictService.queryAllDictItems());
         result.setResult(obj);
         result.success("");
      }
      return result;
   }
   /**
    * é€€å‡ºç™»å½•
    * @param request
    * @param response
    * @return
    */
   @RequestMapping(value = "/logout")
   public Result<Object> logout(HttpServletRequest request,HttpServletResponse response) {
      //用户退出逻辑
       String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
       if(oConvertUtils.isEmpty(token)) {
          return Result.error("退出登录失败!");
       }
       String username = JwtUtil.getUsername(token);
      LoginUser sysUser = sysBaseApi.getUserByName(username);
       if(sysUser!=null) {
         //update-begin--Author:wangshuai  Date:20200714  for:登出日志没有记录人员
         baseCommonService.addLog("用户名: "+sysUser.getRealname()+",退出成功!", CommonConstant.LOG_TYPE_1, null,sysUser);
         //update-end--Author:wangshuai  Date:20200714  for:登出日志没有记录人员
          log.info(" ç”¨æˆ·å:  "+sysUser.getRealname()+",退出成功! ");
          //清空用户登录Token缓存
          redisUtil.del(CommonConstant.PREFIX_USER_TOKEN + token);
          //清空用户登录Shiro权限缓存
         redisUtil.del(CommonConstant.PREFIX_USER_SHIRO_CACHE + sysUser.getId());
         //清空用户的缓存信息(包括部门信息),例如sys:cache:user::<username>
         redisUtil.del(String.format("%s::%s", CacheConstant.SYS_USERS_CACHE, sysUser.getUsername()));
         //调用shiro的logout
         SecurityUtils.getSubject().logout();
          return Result.ok("退出登录成功!");
       }else {
          return Result.error("Token无效!");
       }
   }
   /**
    * èŽ·å–è®¿é—®é‡
    * @return
    */
   @GetMapping("loginfo")
   public Result<JSONObject> loginfo() {
      Result<JSONObject> result = new Result<JSONObject>();
      JSONObject obj = new JSONObject();
      //update-begin--Author:zhangweijian  Date:20190428 for:传入开始时间,结束时间参数
      // èŽ·å–ä¸€å¤©çš„å¼€å§‹å’Œç»“æŸæ—¶é—´
      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 = logService.findTotalVisitCount();
      obj.put("totalVisitCount", totalVisitCount);
      Long todayVisitCount = logService.findTodayVisitCount(dayStart,dayEnd);
      obj.put("todayVisitCount", todayVisitCount);
      Long todayIp = logService.findTodayIp(dayStart,dayEnd);
      //update-end--Author:zhangweijian  Date:20190428 for:传入开始时间,结束时间参数
      obj.put("todayIp", todayIp);
      result.setResult(obj);
      result.success("登录成功");
      return result;
   }
   /**
    * èŽ·å–è®¿é—®é‡
    * @return
    */
   @GetMapping("visitInfo")
   public Result<List<Map<String,Object>>> visitInfo() {
      Result<List<Map<String,Object>>> result = new Result<List<Map<String,Object>>>();
      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();
        List<Map<String,Object>> list = logService.findVisitCount(dayStart, dayEnd);
      result.setResult(oConvertUtils.toLowerCasePageList(list));
      return result;
   }
   /**
    * ç™»é™†æˆåŠŸé€‰æ‹©ç”¨æˆ·å½“å‰éƒ¨é—¨
    * @param user
    * @return
    */
   @RequestMapping(value = "/selectDepart", method = RequestMethod.PUT)
   public Result<JSONObject> selectDepart(@RequestBody SysUser user) {
      Result<JSONObject> result = new Result<JSONObject>();
      String username = user.getUsername();
      if(oConvertUtils.isEmpty(username)) {
         LoginUser sysUser = (LoginUser)SecurityUtils.getSubject().getPrincipal();
         username = sysUser.getUsername();
      }
      //获取登录部门
      String orgCode= user.getOrgCode();
      //获取登录租户
      Integer tenantId = user.getLoginTenantId();
      this.sysUserService.updateUserDepart(username, orgCode,tenantId);
      SysUser sysUser = sysUserService.getUserByName(username);
      JSONObject obj = new JSONObject();
      obj.put("userInfo", sysUser);
      result.setResult(obj);
      return result;
   }
   /**
    * çŸ­ä¿¡ç™»å½•接口
    *
    * @param jsonObject
    * @return
    */
   @PostMapping(value = "/sms")
   public Result<String> sms(@RequestBody JSONObject jsonObject) {
      Result<String> result = new Result<String>();
      String mobile = jsonObject.get("mobile").toString();
      //手机号模式 ç™»å½•模式: "2"  æ³¨å†Œæ¨¡å¼: "1"
      String smsmode=jsonObject.get("smsmode").toString();
      log.info(mobile);
      if(oConvertUtils.isEmpty(mobile)){
         result.setMessage("手机号不允许为空!");
         result.setSuccess(false);
         return result;
      }
      //update-begin-author:taoyan date:2022-9-13 for: VUEN-2245 ã€æ¼æ´žã€‘发现新漏洞待处理20220906
      String redisKey = CommonConstant.PHONE_REDIS_KEY_PRE+mobile;
      Object object = redisUtil.get(redisKey);
      //update-end-author:taoyan date:2022-9-13 for: VUEN-2245 ã€æ¼æ´žã€‘发现新漏洞待处理20220906
      if (object != null) {
         result.setMessage("验证码10分钟内,仍然有效!");
         result.setSuccess(false);
         return result;
      }
      //随机数
      String captcha = RandomUtil.randomNumbers(6);
      JSONObject obj = new JSONObject();
       obj.put("code", captcha);
      try {
         boolean b = false;
         //注册模板
         if (CommonConstant.SMS_TPL_TYPE_1.equals(smsmode)) {
            SysUser sysUser = sysUserService.getUserByPhone(mobile);
            if(sysUser!=null) {
               result.error500(" æ‰‹æœºå·å·²ç»æ³¨å†Œï¼Œè¯·ç›´æŽ¥ç™»å½•!");
               baseCommonService.addLog("手机号已经注册,请直接登录!", CommonConstant.LOG_TYPE_1, null);
               return result;
            }
            b = DySmsHelper.sendSms(mobile, obj, DySmsEnum.REGISTER_TEMPLATE_CODE);
         }else {
            //登录模式,校验用户有效性
            SysUser sysUser = sysUserService.getUserByPhone(mobile);
            result = sysUserService.checkUserIsEffective(sysUser);
            if(!result.isSuccess()) {
               String message = result.getMessage();
               String userNotExist="该用户不存在,请注册";
               if(userNotExist.equals(message)){
                  result.error500("该用户不存在或未绑定手机号");
               }
               return result;
            }
            /**
             * smsmode çŸ­ä¿¡æ¨¡æ¿æ–¹å¼  0 .登录模板、1.注册模板、2.忘记密码模板
             */
            if (CommonConstant.SMS_TPL_TYPE_0.equals(smsmode)) {
               //登录模板
               b = DySmsHelper.sendSms(mobile, obj, DySmsEnum.LOGIN_TEMPLATE_CODE);
            } else if(CommonConstant.SMS_TPL_TYPE_2.equals(smsmode)) {
               //忘记密码模板
               b = DySmsHelper.sendSms(mobile, obj, DySmsEnum.FORGET_PASSWORD_TEMPLATE_CODE);
            }
         }
         if (b == false) {
            result.setMessage("短信验证码发送失败,请稍后重试");
            result.setSuccess(false);
            return result;
         }
         //update-begin-author:taoyan date:2022-9-13 for: VUEN-2245 ã€æ¼æ´žã€‘发现新漏洞待处理20220906
         //验证码10分钟内有效
         redisUtil.set(redisKey, captcha, 600);
         //update-end-author:taoyan date:2022-9-13 for: VUEN-2245 ã€æ¼æ´žã€‘发现新漏洞待处理20220906
         //update-begin--Author:scott  Date:20190812 for:issues#391
         //result.setResult(captcha);
         //update-end--Author:scott  Date:20190812 for:issues#391
         result.setSuccess(true);
      } catch (ClientException e) {
         e.printStackTrace();
         result.error500(" çŸ­ä¿¡æŽ¥å£æœªé…ç½®ï¼Œè¯·è”系管理员!");
         return result;
      }
      return result;
   }
   /**
    * æ‰‹æœºå·ç™»å½•接口
    *
    * @param jsonObject
    * @return
    */
   @ApiOperation("手机号登录接口")
   @PostMapping("/phoneLogin")
   public Result<JSONObject> phoneLogin(@RequestBody JSONObject jsonObject) {
      Result<JSONObject> result = new Result<JSONObject>();
      String phone = jsonObject.getString("mobile");
      //update-begin-author:taoyan date:2022-11-7 for: issues/4109 å¹³å°ç”¨æˆ·ç™»å½•失败锁定用户
      if(isLoginFailOvertimes(phone)){
         return result.error500("该用户登录失败次数过多,请于10分钟后再次登录!");
      }
      //update-end-author:taoyan date:2022-11-7 for: issues/4109 å¹³å°ç”¨æˆ·ç™»å½•失败锁定用户
      //校验用户有效性
      SysUser sysUser = sysUserService.getUserByPhone(phone);
      result = sysUserService.checkUserIsEffective(sysUser);
      if(!result.isSuccess()) {
         return result;
      }
      String smscode = jsonObject.getString("captcha");
      //update-begin-author:taoyan date:2022-9-13 for: VUEN-2245 ã€æ¼æ´žã€‘发现新漏洞待处理20220906
      String redisKey = CommonConstant.PHONE_REDIS_KEY_PRE+phone;
      Object code = redisUtil.get(redisKey);
      //update-end-author:taoyan date:2022-9-13 for: VUEN-2245 ã€æ¼æ´žã€‘发现新漏洞待处理20220906
      if (!smscode.equals(code)) {
         //update-begin-author:taoyan date:2022-11-7 for: issues/4109 å¹³å°ç”¨æˆ·ç™»å½•失败锁定用户
         addLoginFailOvertimes(phone);
         //update-end-author:taoyan date:2022-11-7 for: issues/4109 å¹³å°ç”¨æˆ·ç™»å½•失败锁定用户
         result.setMessage("手机验证码错误");
         return result;
      }
      //用户信息
      userInfo(sysUser, result);
      //添加日志
      baseCommonService.addLog("用户名: " + sysUser.getUsername() + ",登录成功!", CommonConstant.LOG_TYPE_1, null);
      return result;
   }
   /**
    * ç”¨æˆ·ä¿¡æ¯
    *
    * @param sysUser
    * @param result
    * @return
    */
   private Result<JSONObject> userInfo(SysUser sysUser, Result<JSONObject> result) {
      String username = sysUser.getUsername();
      String syspassword = sysUser.getPassword();
      // èŽ·å–ç”¨æˆ·éƒ¨é—¨ä¿¡æ¯
      JSONObject obj = new JSONObject(new LinkedHashMap<>());
      //1.生成token
      String token = JwtUtil.sign(username, syspassword);
      // è®¾ç½®token缓存有效时间
      redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
      redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME * 2 / 1000);
      obj.put("token", token);
      //2.设置登录租户
      Result<JSONObject> loginTenantError = sysUserService.setLoginTenant(sysUser, obj, username,result);
      if (loginTenantError != null) {
         return loginTenantError;
      }
      //3.设置登录用户信息
      obj.put("userInfo", sysUser);
      //4.设置登录部门
      List<SysDepart> departs = sysDepartService.queryUserDeparts(sysUser.getId());
      obj.put("departs", departs);
      if (departs == null || departs.size() == 0) {
         obj.put("multi_depart", 0);
      } else if (departs.size() == 1) {
         sysUserService.updateUserDepart(username, departs.get(0).getOrgCode(),null);
         obj.put("multi_depart", 1);
      } else {
         //查询当前是否有登录部门
         // update-begin--Author:wangshuai Date:20200805 for:如果用戶为选择部门,数据库为存在上一次登录部门,则取一条存进去
         SysUser sysUserById = sysUserService.getById(sysUser.getId());
         if(oConvertUtils.isEmpty(sysUserById.getOrgCode())){
            sysUserService.updateUserDepart(username, departs.get(0).getOrgCode(),null);
         }
         // update-end--Author:wangshuai Date:20200805 for:如果用戶为选择部门,数据库为存在上一次登录部门,则取一条存进去
         obj.put("multi_depart", 2);
      }
      obj.put("sysAllDictItems", sysDictService.queryAllDictItems());
      result.setResult(obj);
      result.success("登录成功");
      return result;
   }
   /**
    * èŽ·å–åŠ å¯†å­—ç¬¦ä¸²
    * @return
    */
   @GetMapping(value = "/getEncryptedString")
   public Result<Map<String,String>> getEncryptedString(){
      Result<Map<String,String>> result = new Result<Map<String,String>>();
      Map<String,String> map = new HashMap(5);
      map.put("key", EncryptedString.key);
      map.put("iv",EncryptedString.iv);
      result.setResult(map);
      return result;
   }
   /**
    * åŽå°ç”Ÿæˆå›¾å½¢éªŒè¯ç  ï¼šæœ‰æ•ˆ
    * @param response
    * @param key
    */
   @ApiOperation("获取验证码")
   @GetMapping(value = "/randomImage/{key}")
   public Result<String> randomImage(HttpServletResponse response,@PathVariable("key") String key){
      Result<String> res = new Result<String>();
      try {
         //生成验证码
         String code = RandomUtil.randomString(BASE_CHECK_CODES,4);
         //存到redis中
         String lowerCaseCode = code.toLowerCase();
         //update-begin-author:taoyan date:2022-9-13 for: VUEN-2245 ã€æ¼æ´žã€‘发现新漏洞待处理20220906
         // åŠ å…¥å¯†é’¥ä½œä¸ºæ··æ·†ï¼Œé¿å…ç®€å•çš„æ‹¼æŽ¥ï¼Œè¢«å¤–éƒ¨åˆ©ç”¨ï¼Œç”¨æˆ·è‡ªå®šä¹‰è¯¥å¯†é’¥å³å¯
         String origin = lowerCaseCode+key+jeecgBaseConfig.getSignatureSecret();
         String realKey = Md5Util.md5Encode(origin, "utf-8");
         //update-end-author:taoyan date:2022-9-13 for: VUEN-2245 ã€æ¼æ´žã€‘发现新漏洞待处理20220906
         redisUtil.set(realKey, lowerCaseCode, 60);
         log.info("获取验证码,Redis key = {},checkCode = {}", realKey, code);
         //返回前端
         String base64 = RandImageUtil.generate(code);
         res.setSuccess(true);
         res.setResult(base64);
      } catch (Exception e) {
         log.error(e.getMessage(), e);
         res.error500("获取验证码失败,请检查redis配置!");
         return res;
      }
      return res;
   }
   /**
    * åˆ‡æ¢èœå•表为vue3的表
    */
   @RequiresRoles({"admin"})
   @GetMapping(value = "/switchVue3Menu")
   public Result<String> switchVue3Menu(HttpServletResponse response) {
      Result<String> res = new Result<String>();
      sysPermissionService.switchVue3Menu();
      return res;
   }
   /**
    * app登录
    * @param sysLoginModel
    * @return
    * @throws Exception
    */
   @RequestMapping(value = "/mLogin", method = RequestMethod.POST)
   public Result<JSONObject> mLogin(@RequestBody SysLoginModel sysLoginModel) throws Exception {
      Result<JSONObject> result = new Result<JSONObject>();
      String username = sysLoginModel.getUsername();
      String password = sysLoginModel.getPassword();
      JSONObject obj = new JSONObject();
      //update-begin-author:taoyan date:2022-11-7 for: issues/4109 å¹³å°ç”¨æˆ·ç™»å½•失败锁定用户
      if(isLoginFailOvertimes(username)){
         return result.error500("该用户登录失败次数过多,请于10分钟后再次登录!");
      }
      //update-end-author:taoyan date:2022-11-7 for: issues/4109 å¹³å°ç”¨æˆ·ç™»å½•失败锁定用户
      //1. æ ¡éªŒç”¨æˆ·æ˜¯å¦æœ‰æ•ˆ
      SysUser sysUser = sysUserService.getUserByName(username);
      result = sysUserService.checkUserIsEffective(sysUser);
      if(!result.isSuccess()) {
         return result;
      }
      //2. æ ¡éªŒç”¨æˆ·åæˆ–密码是否正确
      String userpassword = PasswordUtil.encrypt(username, password, sysUser.getSalt());
      String syspassword = sysUser.getPassword();
      if (!syspassword.equals(userpassword)) {
         //update-begin-author:taoyan date:2022-11-7 for: issues/4109 å¹³å°ç”¨æˆ·ç™»å½•失败锁定用户
         addLoginFailOvertimes(username);
         //update-end-author:taoyan date:2022-11-7 for: issues/4109 å¹³å°ç”¨æˆ·ç™»å½•失败锁定用户
         result.error500("用户名或密码错误");
         return result;
      }
      //3.设置登录部门
      String orgCode = sysUser.getOrgCode();
      if(oConvertUtils.isEmpty(orgCode)) {
         //如果当前用户无选择部门 æŸ¥çœ‹éƒ¨é—¨å…³è”信息
         List<SysDepart> departs = sysDepartService.queryUserDeparts(sysUser.getId());
         //update-begin-author:taoyan date:20220117 for: JTC-1068【app】新建用户,没有设置部门及角色,点击登录提示暂未归属部,一直在登录页面 ä½¿ç”¨æ‰‹æœºå·ç™»å½• å¯æ­£å¸¸
         if (departs == null || departs.size() == 0) {
            /*result.error500("用户暂未归属部门,不可登录!");
            return result;*/
         }else{
            orgCode = departs.get(0).getOrgCode();
            sysUser.setOrgCode(orgCode);
            this.sysUserService.updateUserDepart(username, orgCode,null);
         }
         //update-end-author:taoyan date:20220117 for: JTC-1068【app】新建用户,没有设置部门及角色,点击登录提示暂未归属部,一直在登录页面 ä½¿ç”¨æ‰‹æœºå·ç™»å½• å¯æ­£å¸¸
      }
      //4. è®¾ç½®ç™»å½•租户
      Result<JSONObject> loginTenantError = sysUserService.setLoginTenant(sysUser, obj, username, result);
      if (loginTenantError != null) {
         return loginTenantError;
      }
      //5. è®¾ç½®ç™»å½•用户信息
      obj.put("userInfo", sysUser);
      //6. ç”Ÿæˆtoken
      String token = JwtUtil.sign(username, syspassword);
      // è®¾ç½®è¶…æ—¶æ—¶é—´
      redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
      redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME*2 / 1000);
      //token ä¿¡æ¯
      obj.put("token", token);
      result.setResult(obj);
      result.setSuccess(true);
      result.setCode(200);
      baseCommonService.addLog("用户名: " + username + ",登录成功[移动端]!", CommonConstant.LOG_TYPE_1, null);
      return result;
   }
   /**
    * å›¾å½¢éªŒè¯ç 
    * @param sysLoginModel
    * @return
    */
   @RequestMapping(value = "/checkCaptcha", method = RequestMethod.POST)
   public Result<?> checkCaptcha(@RequestBody SysLoginModel sysLoginModel){
      String captcha = sysLoginModel.getCaptcha();
      String checkKey = sysLoginModel.getCheckKey();
      if(captcha==null){
         return Result.error("验证码无效");
      }
      String lowerCaseCaptcha = captcha.toLowerCase();
      String realKey = Md5Util.md5Encode(lowerCaseCaptcha+checkKey, "utf-8");
      Object checkCode = redisUtil.get(realKey);
      if(checkCode==null || !checkCode.equals(lowerCaseCaptcha)) {
         return Result.error("验证码错误");
      }
      return Result.ok();
   }
   /**
    * ç™»å½•二维码
    */
   @ApiOperation(value = "登录二维码", notes = "登录二维码")
   @GetMapping("/getLoginQrcode")
   public Result<?>  getLoginQrcode() {
      String qrcodeId = CommonConstant.LOGIN_QRCODE_PRE+IdWorker.getIdStr();
      //定义二维码参数
      Map params = new HashMap(5);
      params.put("qrcodeId", qrcodeId);
      //存放二维码唯一标识30秒有效
      redisUtil.set(CommonConstant.LOGIN_QRCODE + qrcodeId, qrcodeId, 30);
      return Result.OK(params);
   }
   /**
    * æ‰«ç äºŒç»´ç 
    */
   @ApiOperation(value = "扫码登录二维码", notes = "扫码登录二维码")
   @PostMapping("/scanLoginQrcode")
   public Result<?> scanLoginQrcode(@RequestParam String qrcodeId, @RequestParam String token) {
      Object check = redisUtil.get(CommonConstant.LOGIN_QRCODE + qrcodeId);
      if (oConvertUtils.isNotEmpty(check)) {
         //存放token给前台读取
         redisUtil.set(CommonConstant.LOGIN_QRCODE_TOKEN+qrcodeId, token, 60);
      } else {
         return Result.error("二维码已过期,请刷新后重试");
      }
      return Result.OK("扫码成功");
   }
   /**
    * èŽ·å–ç”¨æˆ·æ‰«ç åŽä¿å­˜çš„token
    */
   @ApiOperation(value = "获取用户扫码后保存的token", notes = "获取用户扫码后保存的token")
   @GetMapping("/getQrcodeToken")
   public Result getQrcodeToken(@RequestParam String qrcodeId) {
      Object token = redisUtil.get(CommonConstant.LOGIN_QRCODE_TOKEN + qrcodeId);
      Map result = new HashMap(5);
      Object qrcodeIdExpire = redisUtil.get(CommonConstant.LOGIN_QRCODE + qrcodeId);
      if (oConvertUtils.isEmpty(qrcodeIdExpire)) {
         //二维码过期通知前台刷新
         result.put("token", "-2");
         return Result.OK(result);
      }
      if (oConvertUtils.isNotEmpty(token)) {
         result.put("success", true);
         result.put("token", token);
      } else {
         result.put("token", "-1");
      }
      return Result.OK(result);
   }
   /**
    * ç™»å½•失败超出次数5 è¿”回true
    * @param username
    * @return
    */
   private boolean isLoginFailOvertimes(String username){
      String key = CommonConstant.LOGIN_FAIL + username;
      Object failTime = redisUtil.get(key);
      if(failTime!=null){
         Integer val = Integer.parseInt(failTime.toString());
         if(val>5){
            return true;
         }
      }
      return false;
   }
   /**
    * è®°å½•登录失败次数
    * @param username
    */
   private void addLoginFailOvertimes(String username){
      String key = CommonConstant.LOGIN_FAIL + username;
      Object failTime = redisUtil.get(key);
      Integer val = 0;
      if(failTime!=null){
         val = Integer.parseInt(failTime.toString());
      }
      // 1小时
      redisUtil.set(key, ++val, 3600);
   }
}