Jelajahi Sumber

优化登录接口

tsurumure 9 bulan lalu
induk
melakukan
f34858aaf7

+ 4 - 0
src/main/java/com/backendsys/modules/system/entity/SysUserInfo.java

@@ -56,4 +56,8 @@ public class SysUserInfo {
     @TableField(exist = false)
     private List<String> modules;
 
+    @TableField(exist = false)
+    private String token_expiration;
+    @TableField(exist = false)
+    private String token;
 }

+ 2 - 1
src/main/java/com/backendsys/modules/system/service/SysAuthV2Service.java

@@ -2,6 +2,7 @@ package com.backendsys.modules.system.service;
 
 import com.backendsys.modules.system.entity.SysAuth;
 import com.backendsys.modules.system.entity.SysMobileArea;
+import com.backendsys.modules.system.entity.SysUserInfo;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
 
@@ -14,6 +15,6 @@ public interface SysAuthV2Service {
     void renderCaptcha(HttpServletResponse response) throws IOException;
     List<SysMobileArea> getMobileAreaList(SysMobileArea sysMobileArea);
 
-    Map<String, Object> login(SysAuth sysAuth);
+    SysUserInfo login(SysAuth sysAuth);
 
 }

+ 99 - 44
src/main/java/com/backendsys/modules/system/service/impl/SysAuthV2ServiceImpl.java

@@ -1,57 +1,74 @@
 package com.backendsys.modules.system.service.impl;
 
-import com.backendsys.config.Kaptcha.KaptchaUtil;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.json.JSONUtil;
 import com.backendsys.exception.CustException;
 import com.backendsys.modules.common.config.redis.utils.RedisUtil;
+import com.backendsys.modules.common.config.security.entity.SecurityUserInfo;
 import com.backendsys.modules.common.config.security.utils.CaptchaUtil;
 import com.backendsys.modules.common.config.security.utils.CountUtilV2;
 import com.backendsys.modules.common.config.security.utils.HttpRequestUtil;
+import com.backendsys.modules.common.config.security.utils.JwtUtil;
 import com.backendsys.modules.system.dao.SysMobileAreaDao;
 import com.backendsys.modules.system.dao.SysUserDao;
+import com.backendsys.modules.system.dao.SysUserInfoDao;
 import com.backendsys.modules.system.entity.SysAuth;
 import com.backendsys.modules.system.entity.SysMobileArea;
 import com.backendsys.modules.system.entity.SysUser;
+import com.backendsys.modules.system.entity.SysUserInfo;
 import com.backendsys.modules.system.service.SysAuthV2Service;
+import com.backendsys.modules.system.service.SysUserV2Service;
 import com.backendsys.utils.response.ResultEnum;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.google.code.kaptcha.Producer;
 import jakarta.servlet.ServletOutputStream;
-import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
 import javax.imageio.ImageIO;
 import java.awt.image.BufferedImage;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.util.Date;
 import java.util.List;
 import java.util.Map;
+import java.util.UUID;
 import java.util.concurrent.TimeUnit;
 
 @Service
 public class SysAuthV2ServiceImpl implements SysAuthV2Service {
 
-    @Autowired
-    private HttpRequestUtil httpRequestUtil;
     @Autowired
     private RedisUtil redisUtil;
     @Autowired
+    private JwtUtil jwtUtil;
+    @Autowired
+    private HttpRequestUtil httpRequestUtil;
+    @Autowired
     private CountUtilV2 countUtilV2;
     @Autowired
     private CaptchaUtil captchaUtil;
-
     @Autowired
     private Producer captchaProducer;
-    @Value("${CAPTCHA_DURATION}")
-    private Integer CAPTCHA_DURATION;
 
     @Autowired
     private SysUserDao sysUserDao;
     @Autowired
+    private SysUserInfoDao sysUserInfoDao;
+    @Autowired
+    private SysUserV2Service sysUserV2Service;
+    @Autowired
     private SysMobileAreaDao sysMobileAreaDao;
 
+    @Value("${CAPTCHA_DURATION}")
+    private Integer CAPTCHA_DURATION;
+    @Value("${TOKEN_DURATION_SYSTEM}")
+    private Integer TOKEN_DURATION_SYSTEM;
+
     @Override
     public void renderCaptcha(HttpServletResponse response) throws IOException {
         byte[] captchaChallengeAsJpeg;
@@ -85,54 +102,92 @@ public class SysAuthV2ServiceImpl implements SysAuthV2Service {
         return sysMobileAreaDao.selectMobileAreaList(sysMobileArea);
     }
 
-    @Override
-    public Map<String, Object> login(SysAuth sysAuth) {
+    // [方法] 登录失败 (errMsg: 错误提示文本, username: 用户名, intercept: 是否拦截)
+    private void loginFail(String errMsg, String username, Boolean isIntercept) {
+        redisUtil.delete(httpRequestUtil.getKaptchaKey());
+        // 添加登录错误的冻结标记
+        if (isIntercept) countUtilV2.setErrorCount("login-error", username);
+        throw new CustException(errMsg, ResultEnum.INVALID_CREDENTIALS.getCode());
+    }
 
-//        System.out.println(sysAuth);
-//        System.out.println(httpRequestUtil.getIpAddr());
+    // [方法] 登录成功
+    private SysUserInfo loginSuccess(SysAuth sysAuth) {
+
+        // [查询] 登录的用户信息
+        SysUserInfo sysUserInfo = sysUserV2Service.selectUserInfo(sysAuth.getUser_id());
+
+        // 清除缓存
+        redisUtil.delete(httpRequestUtil.getKaptchaKey());                       // 作废验证码密钥
+        redisUtil.delete("token:id:" + sysUserInfo.getLast_login_uuid());   // 删除旧的登录缓存 (Redis)
+
+        // 判断用户是否审核
+        Integer auditStatus = sysUserInfo.getAudit_status();
+        if (auditStatus != null && auditStatus.equals(1)) throw new CustException("请等待管理员审核");
+        if (auditStatus != null && auditStatus.equals(-1)) throw new CustException("审核未通过,请与客服联系");
+
+        // 判断用户是否启用
+        Integer status = sysUserInfo.getStatus();
+        if (status != null && status.equals(-1)) throw new CustException("该用户已被禁用,请与客服联系");
+
+        // 判断用户是否已删除
+        Integer delFlag = sysUserInfo.getDel_flag();
+        if (delFlag != null && delFlag.equals(1)) throw new CustException("用户状态异常,请与客服联系");
+
+        // 设置 最后一次的登录信息 (uuid, ip, 登录时间)
+        String uuid = String.valueOf(UUID.randomUUID());
+        sysUserInfo.setLast_login_uuid(uuid);
+        sysUserInfo.setLast_login_ip(httpRequestUtil.getIpAddr());
+        sysUserInfo.setLast_login_time(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
+        sysUserInfoDao.updateById(sysUserInfo);
+
+        // 设置 Token 过期时间
+        Integer isRemember = sysAuth.getIs_remember();
+        Integer tokenDuration = (isRemember != null && isRemember.equals(1)) ? TOKEN_DURATION_SYSTEM * 7 : TOKEN_DURATION_SYSTEM;
+        Date tokenExpiration = new Date((new Date()).getTime() + tokenDuration);
+        sysUserInfo.setToken_expiration(DateUtil.format(tokenExpiration, "yyyy-MM-dd HH:mm:ss"));
+
+        // 生成 Token
+        SecurityUserInfo securityUserInfo = JSONUtil.toBean(JSONUtil.parseObj(sysUserInfo), SecurityUserInfo.class);
+        String token = jwtUtil.createJwtToken(securityUserInfo);
+        String tokenRedisKey = "token:id:" + uuid;
+        redisUtil.setCacheObject(tokenRedisKey, token, tokenDuration, TimeUnit.MILLISECONDS);
+        sysUserInfo.setToken(token);
+
+        return sysUserInfo;
+    }
 
-        String username = sysAuth.getUsername();
-        String password = sysAuth.getPassword();
-        String captcha = sysAuth.getCaptcha();
+    @Override
+    @Transactional
+    public SysUserInfo login(SysAuth sysAuth) {
 
-        // 判断是否处于 5次的错误状态
+        // 判断是否处于登录错误的冻结状态 (2分钟内错误5次,则出现冻结提示)
         countUtilV2.checkErrorStatus("login-error", sysAuth.getUsername());
 
         // [Method] 判断验证码是否正确 (RedisKey: (ua + ip))
-        String captchaRedisKey = httpRequestUtil.getKaptchaKey();
-        if (!captchaUtil.isCaptchaValid(captcha, captchaRedisKey)) {
-            redisUtil.delete(captchaRedisKey);
-            throw new CustException("验证码错误", ResultEnum.INVALID_CREDENTIALS.getCode());
+        if (!captchaUtil.isCaptchaValid(sysAuth.getCaptcha(), httpRequestUtil.getKaptchaKey())) {
+            loginFail("验证码错误", sysAuth.getUsername(), false);
+            return null;
         }
 
         // [Method] 判断 用户 是否存在 && 密码是否正确
-        SysUser sysUser = sysUserDao.selectOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUsername, username));
+        SysUser sysUser = sysUserDao.selectOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUsername, sysAuth.getUsername()));
         if (sysUser == null) {
-            redisUtil.delete(captchaRedisKey);
-            // 添加错误标记 (2分钟内错误5次,则出现冻结提示)
-            countUtilV2.setErrorCount("login-error", username);
-            throw new CustException("用户名或密码错误", ResultEnum.INVALID_CREDENTIALS.getCode());
+            // [登录失败] 用户不存在
+            loginFail("用户名或密码错误", sysAuth.getUsername(), true);
+            return null;
+        } else {
+
+            // [登录失败] 密码不正确
+            BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
+            if (!encoder.matches(sysAuth.getPassword(), sysUser.getPassword())) {
+                loginFail("用户名或密码错误", sysAuth.getUsername(), true);
+            }
+
+            // [登录成功]
+            sysAuth.setUser_id(sysUser.getId());
+            return loginSuccess(sysAuth);
         }
-        System.out.println(sysUser);
-
-//        Map<String, Object> sysUserSimple = sysUserMapper.queryUserByIdOrName(null, username, null, null);
-//        if (sysUserSimple != null) {
-//            sysUserDTO.setUser_id((Long) sysUserSimple.get("id"));
-//        }
-//        if (!(sysUserSimple != null && isUserPasswordValid(sysUserSimple, password))) {
-//            stringRedisTemplate.delete(captchaRedisKey);
-//            // 添加错误标记 (2分钟内错误5次,则出现提示)
-//            countUtil.setErrorCount("login-error", username);
-//            throw new CustException("用户名或密码错误", ResultEnum.INVALID_CREDENTIALS.getCode());
-//        }
-//
-//        // 1.作废验证码密钥
-//        stringRedisTemplate.delete(captchaRedisKey);
-//
-//        // [登录成功]
-//        Map<String, Object> result = loginSuccess(request, sysUserDTO);
-
-        return null;
+
     }
 
 }