package com.trafficaudit.security.controller; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.trafficaudit.common.Result; import com.trafficaudit.security.captcha.CaptchaService; import com.trafficaudit.security.utils.JwtUtils; import com.trafficaudit.system.entity.User; import com.trafficaudit.system.mapper.UserMapper; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.web.bind.annotation.*; import org.springframework.beans.factory.annotation.Value; import javax.annotation.Resource; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @RestController @RequestMapping("/api/auth") public class LoginController { @Resource private JwtUtils jwtUtils; @Resource private CaptchaService captchaService; @Resource private UserMapper userMapper; @Resource private PasswordEncoder passwordEncoder; @Value("${app.captcha.required:true}") private boolean captchaRequired; @PostMapping("/login") public Result> login(@RequestBody Map params) { String username = (String) params.get("username"); String password = (String) params.get("password"); String captchaId = (String) params.get("captchaId"); List clickIds = strList(params.get("captchaClickIds")); if (captchaRequired) { CaptchaService.ConsumeResult cr = captchaService.consume(captchaId, clickIds); if (cr == CaptchaService.ConsumeResult.NOT_FOUND) { return Result.error(4002, "验证码不存在或已过期,请刷新重试"); } if (cr == CaptchaService.ConsumeResult.NOT_VERIFIED) { return Result.error(4003, "请先完成行为验证"); } if (cr == CaptchaService.ConsumeResult.WRONG) { return Result.error(4001, "行为验证未通过,请重新验证"); } } if (username == null || username.trim().isEmpty() || password == null || password.isEmpty()) { return Result.error(401, "用户名或密码错误"); } User user = userMapper.selectOne(new LambdaQueryWrapper() .eq(User::getUsername, username.trim())); if (user == null || !Integer.valueOf(1).equals(user.getStatus())) { return Result.error(401, "用户名或密码错误"); } String encoded = user.getPassword(); boolean ok; try { ok = encoded != null && passwordEncoder.matches(password, encoded); } catch (IllegalArgumentException e) { // 库中密码不是合法 BCrypt 时回退为明文对比(避免旧数据无法登录) ok = encoded != null && encoded.equals(password); } if (!ok) { return Result.error(401, "用户名或密码错误"); } String token = jwtUtils.generateToken(username.trim()); Map data = new HashMap<>(); data.put("token", token); data.put("username", username.trim()); data.put("realName", user.getRealName()); data.put("modules", user.getModules() == null ? "" : user.getModules()); return Result.ok(data); } /** 用户修改自己的密码:需提供原密码,新密码至少 6 位 */ @PostMapping("/change-password") public Result changePassword(@RequestHeader(value = "Authorization", required = false) String auth, @RequestBody Map params) { String username = jwtUtils.resolveUsername(auth); if (username == null) { return Result.error(401, "未登录或登录已过期"); } String oldPassword = (String) params.get("oldPassword"); String newPassword = (String) params.get("newPassword"); if (oldPassword == null || oldPassword.isEmpty()) { return Result.error(400, "请输入原密码"); } if (newPassword == null || newPassword.length() < 6) { return Result.error(400, "新密码长度不能少于 6 位"); } if (newPassword.equals(oldPassword)) { return Result.error(400, "新密码不能与原密码相同"); } User user = userMapper.selectOne(new LambdaQueryWrapper().eq(User::getUsername, username)); if (user == null) { return Result.error(404, "用户不存在"); } String encoded = user.getPassword(); boolean ok; try { ok = encoded != null && passwordEncoder.matches(oldPassword, encoded); } catch (IllegalArgumentException e) { // 库中密码不是合法 BCrypt 时回退为明文对比(与登录一致) ok = encoded != null && encoded.equals(oldPassword); } if (!ok) { return Result.error(400, "原密码错误"); } user.setPassword(passwordEncoder.encode(newPassword)); userMapper.updateById(user); return Result.ok(null); } @GetMapping("/captcha-config") public Result> captchaConfig() { Map data = new HashMap<>(); data.put("required", captchaRequired); return Result.ok(data); } @SuppressWarnings("unchecked") private List strList(Object o) { if (o instanceof List) { return (List) o; } return Collections.emptyList(); } }