From e0f9952773a77fb3b2bebf4a2cc43e5141a4063d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E6=AC=A7=EF=BC=88=E6=9E=97=E5=B9=B3=E5=87=A1?= =?UTF-8?q?=EF=BC=89?= Date: Tue, 17 Jun 2025 18:50:02 +0800 Subject: [PATCH] =?UTF-8?q?=E9=89=B4=E6=9D=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/.cache/.Apifox_Helper/.toolWindow.db | Bin 122880 -> 122880 bytes .../van/business/config/SecurityConfig.java | 3 +- .../controller/login/AuthController.java | 26 ++++++++++---- .../cn/van/business/filter/JwtAuthFilter.java | 1 + .../business/service/AdminUserService.java | 5 ++- .../java/cn/van/business/util/JwtUtils.java | 2 +- src/main/java/cn/van/business/util/Util.java | 32 ++++++++++++++++++ 7 files changed, 59 insertions(+), 10 deletions(-) diff --git a/.idea/.cache/.Apifox_Helper/.toolWindow.db b/.idea/.cache/.Apifox_Helper/.toolWindow.db index c9a9adbd2389e47e356050f8bab23d12f7ca2b62..a0438b11f17c45021ab72c69fea2b33856eca5b5 100644 GIT binary patch delta 127 zcmZoTz}|3xeS$Qj{6raNM){2iOX9hhWdj)GPRY)c4cIs_KzQSVPn?48%p$&`%Dg}z z3LZJt@1&BVnlKZ!y9j{J7{Ne~lEcqU(q aS7BvVVfJO5ys=iH`S$$nx92meIsgE6ASi$U delta 79 zcmV-V0I>gnzz2Z92ap>99+4bF0Uohnq+bUD9hm?g${n*IAb1I}pg|Lnpw+XPeQN>; l0w1>kAKV|ev5`;{v7lQF1SA7Z0h6(PAcNbVx7(iqB|t!Q9FhP4 diff --git a/src/main/java/cn/van/business/config/SecurityConfig.java b/src/main/java/cn/van/business/config/SecurityConfig.java index e2e9c8e..a57ed58 100644 --- a/src/main/java/cn/van/business/config/SecurityConfig.java +++ b/src/main/java/cn/van/business/config/SecurityConfig.java @@ -10,6 +10,7 @@ import org.springframework.security.authentication.dao.DaoAuthenticationProvider import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.core.session.SessionRegistry; import org.springframework.security.core.session.SessionRegistryImpl; @@ -39,7 +40,7 @@ public class SecurityConfig { provider.setPasswordEncoder(passwordEncoder); http - .csrf(csrf -> csrf.disable()) + .csrf(AbstractHttpConfigurer::disable) .sessionManagement(session -> session .sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class) diff --git a/src/main/java/cn/van/business/controller/login/AuthController.java b/src/main/java/cn/van/business/controller/login/AuthController.java index f00f3c7..cf10101 100644 --- a/src/main/java/cn/van/business/controller/login/AuthController.java +++ b/src/main/java/cn/van/business/controller/login/AuthController.java @@ -15,6 +15,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; import org.springframework.web.bind.annotation.*; import java.util.concurrent.TimeUnit; @@ -41,7 +42,7 @@ public class AuthController { private static final String USER_TOKEN_PREFIX = "user:token:"; @PostMapping("/login") - public ApiResponse login(@RequestBody LoginRequest request) { + public ApiResponse login(@RequestBody LoginRequest request) { logger.info("用户登录"); logger.info("用户名:{}", request.getUsername()); logger.info("密码:{}", request.getPassword()); @@ -49,28 +50,39 @@ public class AuthController { logger.info("生成的验证码:{}", request.getGeneratedCaptcha()); // 1. 基础校验 if (StringUtils.isBlank(request.getUsername()) || StringUtils.isBlank(request.getPassword())) { - throw new RuntimeException("用户名或密码不能为空"); + logger.error("用户名或密码不能为空"); + return ApiResponse.badRequest(); } // 2. 验证码校验 if (!captchaService.validateCaptcha(request.getCaptcha(), request.getGeneratedCaptcha())) { - throw new RuntimeException("验证码错误"); + logger.error("验证码错误"); + return ApiResponse.badRequest(); } -// 在验证码校验后、认证前添加防爆破逻辑 + // 在验证码校验后、认证前添加防爆破逻辑 String loginFailKey = "login:fail:" + request.getUsername(); Long failCount = redisTemplate.opsForValue().increment(loginFailKey); if (failCount != null && failCount > 5) { - throw new RuntimeException("尝试次数过多,请稍后再试"); + logger.error("尝试次数过多,请稍后再试"); + return ApiResponse.badRequest(); + }else { + redisTemplate.expire(loginFailKey, 5, TimeUnit.MINUTES); } // 3. 用户认证(Spring Security 标准流程) - Authentication authentication = authenticationManager.authenticate( - new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword())); + logger.info("3. 用户认证(Spring Security 标准流程)"); + try { + Authentication authentication = authenticationManager.authenticate( + new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword())); + } catch (Exception e) { + logger.error("用户认证失败:{}", e.getMessage()); + } // 4. 生成 JWT Token logger.info("用户认证成功"); String token = jwtUtils.generateToken(request.getUsername()); String refreshToken = generateRefreshToken(request.getUsername()); + logger.info("生成 JWT Token:{}", token); // 5. 存入 Redis saveUserToken(request.getUsername(), token, jwtUtils.getExpiration(token)); diff --git a/src/main/java/cn/van/business/filter/JwtAuthFilter.java b/src/main/java/cn/van/business/filter/JwtAuthFilter.java index e544d8d..51a3190 100644 --- a/src/main/java/cn/van/business/filter/JwtAuthFilter.java +++ b/src/main/java/cn/van/business/filter/JwtAuthFilter.java @@ -31,6 +31,7 @@ public class JwtAuthFilter extends OncePerRequestFilter { @NonNull FilterChain filterChain) throws ServletException, IOException { try { + logger.debug("JwtAuthFilter.doFilterInternal"); String jwt = parseJwt(request); if (jwt != null && jwtUtils.validateToken(jwt)) { String username = jwtUtils.extractUsername(jwt); diff --git a/src/main/java/cn/van/business/service/AdminUserService.java b/src/main/java/cn/van/business/service/AdminUserService.java index d69378f..5be6f3a 100644 --- a/src/main/java/cn/van/business/service/AdminUserService.java +++ b/src/main/java/cn/van/business/service/AdminUserService.java @@ -1,6 +1,8 @@ package cn.van.business.service; +import cn.hutool.crypto.digest.MD5; import cn.van.business.model.user.AdminUser; +import cn.van.business.util.Util; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; @@ -19,7 +21,8 @@ public class AdminUserService { // 初始化一个测试用户(生产环境应从数据库加载) AdminUser user = new AdminUser(); user.setUsername("van"); - user.setPassword(new BCryptPasswordEncoder().encode("LK.807878712")); + String password = Util.md5("LK.807878712"); + user.setPassword(new BCryptPasswordEncoder().encode(password)); users.put("van", user); } diff --git a/src/main/java/cn/van/business/util/JwtUtils.java b/src/main/java/cn/van/business/util/JwtUtils.java index 439898a..66d3ed3 100644 --- a/src/main/java/cn/van/business/util/JwtUtils.java +++ b/src/main/java/cn/van/business/util/JwtUtils.java @@ -14,7 +14,7 @@ import java.util.Date; @Component public class JwtUtils { - private final String secret = "your-secret-key"; // 应配置在 application.yml 中 + private final String secret = "7b78f5cc9735091442361c78b863607d"; // 应配置在 application.yml 中 private final long expiration = 86400000 * 7; // 24小时 /** diff --git a/src/main/java/cn/van/business/util/Util.java b/src/main/java/cn/van/business/util/Util.java index a9f7976..665b90f 100644 --- a/src/main/java/cn/van/business/util/Util.java +++ b/src/main/java/cn/van/business/util/Util.java @@ -13,6 +13,8 @@ import org.springframework.web.util.HtmlUtils; import java.io.*; import java.math.BigDecimal; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.*; /** @@ -23,6 +25,36 @@ Util { private static final Logger log = LoggerFactory.getLogger(Util.class); + /** + * 将字符串转换为 MD5 摘要 + * + * @param input 原始字符串 + * @return MD5 加密后的十六进制字符串 + */ + public static String md5(String input) { + try { + // 创建 MessageDigest 实例,指定 MD5 算法 + MessageDigest md = MessageDigest.getInstance("MD5"); + + // 将输入字符串转换为字节数组并进行哈希计算 + byte[] messageDigest = md.digest(input.getBytes()); + + // 将字节数组转换为十六进制字符串 + StringBuilder hexString = new StringBuilder(); + for (byte b : messageDigest) { + String hex = Integer.toHexString(0xff & b); + if (hex.length() == 1) + hexString.append('0'); // 补零 + hexString.append(hex); + } + + return hexString.toString(); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("MD5加密失败", e); + } + } + + /** * byte数组倒序 *