Browse Source

1.29 验证码

huangqizheng/feature-20260129114800-验证码^2
huangqizhen 4 weeks ago
parent
commit
e8efd5fe63
  1. 6
      pom.xml
  2. 31
      src/main/java/com/example/demo/config/KaptchaConfig.java
  3. 36
      src/main/java/com/example/demo/controller/coin/AdminController.java
  4. 49
      src/main/java/com/example/demo/controller/coin/CaptchaController.java
  5. 6
      src/main/java/com/example/demo/domain/entity/Admin.java
  6. 1
      src/main/java/com/example/demo/security/SecurityConfig.java

6
pom.xml

@ -42,6 +42,12 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId> <groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId> <artifactId>poi-ooxml</artifactId>
<version>5.2.3</version> <version>5.2.3</version>

31
src/main/java/com/example/demo/config/KaptchaConfig.java

@ -0,0 +1,31 @@
// com.example.demo.config.KaptchaConfig.java
package com.example.demo.config;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Properties;
@Configuration
public class KaptchaConfig {
@Bean
public DefaultKaptcha defaultKaptcha() {
DefaultKaptcha kaptcha = new DefaultKaptcha();
Properties properties = new Properties();
properties.setProperty("kaptcha.image.width", "130");
properties.setProperty("kaptcha.image.height", "45");
properties.setProperty("kaptcha.textproducer.char.length", "4");
properties.setProperty("kaptcha.textproducer.font.size", "35");
properties.setProperty("kaptcha.textproducer.font.color", "black");
properties.setProperty("kaptcha.textproducer.char.space", "5");
properties.setProperty("kaptcha.obscurificator.impl", "com.google.code.kaptcha.impl.WaterRipple");
properties.setProperty("kaptcha.noise.impl", "com.google.code.kaptcha.impl.DefaultNoise");
kaptcha.setConfig(new Config(properties));
return kaptcha;
}
}

36
src/main/java/com/example/demo/controller/coin/AdminController.java

@ -12,6 +12,7 @@ import com.example.demo.service.coin.TranslationService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@ -37,6 +38,8 @@ public class AdminController {
private LanguageTranslationUtil languageTranslationUtil; private LanguageTranslationUtil languageTranslationUtil;
@Autowired @Autowired
private TranslationService translationService; private TranslationService translationService;
@Autowired
private StringRedisTemplate redisTemplate;
@PostMapping("/test") @PostMapping("/test")
public void testGetAdmin() { public void testGetAdmin() {
@ -48,23 +51,50 @@ public class AdminController {
@Log("用户登录") @Log("用户登录")
@PostMapping("/login") @PostMapping("/login")
public Result login(@RequestBody Admin admin, @RequestHeader(defaultValue = "zh_CN") String lang) { public Result login(@RequestBody Admin admin, @RequestHeader(defaultValue = "zh_CN") String lang) {
try { try {
// ====== 新增验证码校验逻辑 ======
if (admin.getCaptcha() == null || admin.getUuid() == null) {
String errorMsg = "验证码或验证码ID缺失";
String translatedErrorMsg = languageTranslationUtil.translate(errorMsg, lang);
return Result.error(translatedErrorMsg);
}
String cacheCode = redisTemplate.opsForValue().get("CAPTCHA:" + admin.getUuid());
if (cacheCode == null) {
String errorMsg = "验证码已过期,请重新获取";
String translatedErrorMsg = languageTranslationUtil.translate(errorMsg, lang);
return Result.error(translatedErrorMsg);
}
if (!cacheCode.equalsIgnoreCase(admin.getCaptcha())) {
String errorMsg = "验证码错误";
String translatedErrorMsg = languageTranslationUtil.translate(errorMsg, lang);
return Result.error(translatedErrorMsg);
}
// ====== 验证码校验结束 ======
// 解析语言代码 // 解析语言代码
String languageCode = parseLanguageCode(lang); String languageCode = parseLanguageCode(lang);
// 如果不是中文环境将输入的翻译字段转换为中文简体
if (!"zh".equalsIgnoreCase(languageCode) && !"zh_cn".equalsIgnoreCase(languageCode)) { if (!"zh".equalsIgnoreCase(languageCode) && !"zh_cn".equalsIgnoreCase(languageCode)) {
convertLoginFieldsToChinese(admin, languageCode); convertLoginFieldsToChinese(admin, languageCode);
} }
// 执行登录此时 admin 包含用户名密码
admin = adminService.login(admin); admin = adminService.login(admin);
// 登录成功后删除已使用的验证码防止重放
redisTemplate.delete("CAPTCHA:" + admin.getUuid());
// 生成 token
String token = JWTUtil.createJWT(admin); String token = JWTUtil.createJWT(admin);
// 对返回的管理员信息进行多语言转换
// 多语言转换
translateAdminInfoForLogin(admin, lang); translateAdminInfoForLogin(admin, lang);
admin.setPassword(null); admin.setPassword(null);
return Result.success(token, admin); return Result.success(token, admin);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
log.error(e.getMessage()); log.error(e.getMessage());

49
src/main/java/com/example/demo/controller/coin/CaptchaController.java

@ -0,0 +1,49 @@
// com.example.demo.controller.CaptchaController.java
package com.example.demo.controller.coin;
import com.google.code.kaptcha.Producer;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
@RestController
public class CaptchaController {
@Autowired
private Producer kaptchaProducer;
@Autowired
private StringRedisTemplate redisTemplate;
/**
* 获取图形验证码
* @param uuid 前端生成的唯一标识用于关联验证码
*/
@GetMapping("/captcha")
public void captcha(@RequestParam String uuid, HttpServletResponse response) throws IOException {
if (uuid == null || uuid.trim().isEmpty()) {
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "uuid is required");
return;
}
// 生成验证码文本和图片
String code = kaptchaProducer.createText();
BufferedImage image = kaptchaProducer.createImage(code);
// 存入 Redis5分钟过期
redisTemplate.opsForValue().set("CAPTCHA:" + uuid, code, 5, TimeUnit.MINUTES);
// 输出图片
response.setHeader("Cache-Control", "no-store");
response.setContentType("image/jpeg");
ImageIO.write(image, "jpg", response.getOutputStream());
}
}

6
src/main/java/com/example/demo/domain/entity/Admin.java

@ -3,6 +3,7 @@ package com.example.demo.domain.entity;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import jakarta.validation.constraints.NotBlank;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
@ -34,12 +35,17 @@ public class Admin implements UserDetails, Serializable {
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private Date createTime; // 创建时间 private Date createTime; // 创建时间
@NotBlank(message = "验证码不能为空")
private String captcha;
@NotBlank(message = "验证码ID不能为空")
private String uuid; // 用于从 Redis 中取验证码
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private Date updateTime; // 更新时间 private Date updateTime; // 更新时间
private Integer roleId; private Integer roleId;
@Override @Override
@JsonIgnore @JsonIgnore
public Collection<? extends GrantedAuthority> getAuthorities() { public Collection<? extends GrantedAuthority> getAuthorities() {

1
src/main/java/com/example/demo/security/SecurityConfig.java

@ -61,6 +61,7 @@ public class SecurityConfig {
.requestMatchers( HttpMethod.POST, .requestMatchers( HttpMethod.POST,
// 用户不登录就可以访问的路径 // 用户不登录就可以访问的路径
"/admin/login","/upload/**","/detailY/ERP","/home/java/haiwaiyanfa/gold1/**","/home/java/haiwaiyanfa/**","/statistics/**","/Mysql/**","/Temporary/**","/cashCollection/syncToCashRecord").permitAll() "/admin/login","/upload/**","/detailY/ERP","/home/java/haiwaiyanfa/gold1/**","/home/java/haiwaiyanfa/**","/statistics/**","/Mysql/**","/Temporary/**","/cashCollection/syncToCashRecord").permitAll()
.requestMatchers(HttpMethod.GET, "/captcha").permitAll()
.requestMatchers( .requestMatchers(
"/error","alipay/**","/upload/**","/home/java/haiwaiyanfa/gold1/**","/home/java/haiwaiyanfa/**" "/error","alipay/**","/upload/**","/home/java/haiwaiyanfa/gold1/**","/home/java/haiwaiyanfa/**"
).permitAll() ).permitAll()

Loading…
Cancel
Save