“mitao”
2026-04-03 8e9d568c2f81de2568b127f0052d89c7b10fab0b
feat(management):验证码生成接口
3个文件已删除
6个文件已添加
5个文件已修改
591 ■■■■■ 已修改文件
xp-robotaxi-account-boot/pom.xml 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/config/CaptchaConfig.java 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/config/KaptchaTextCreator.java 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/config/properties/CaptchaProperties.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/controller/CaptchaController.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/service/IValidateCodeService.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/service/impl/ValidateCodeServiceImpl.java 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-common/xp-common-security/src/main/java/com/xiaopeng/common/security/config/WebMvcConfig.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-gateway-boot/src/main/java/com/xiaopeng/gateway/config/CaptchaConfig.java 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-gateway-boot/src/main/java/com/xiaopeng/gateway/config/KaptchaTextCreator.java 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-gateway-boot/src/main/java/com/xiaopeng/gateway/config/RouterFunctionConfiguration.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-gateway-boot/src/main/java/com/xiaopeng/gateway/handler/ValidateCodeHandler.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-gateway-boot/src/main/java/com/xiaopeng/gateway/service/ValidateCodeService.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-gateway-boot/src/main/java/com/xiaopeng/gateway/service/impl/ValidateCodeServiceImpl.java 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/pom.xml
@@ -101,6 +101,10 @@
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>pro.fessional</groupId>
            <artifactId>kaptcha</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
        </dependency>
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/config/CaptchaConfig.java
New file
@@ -0,0 +1,71 @@
package com.xiaopeng.account.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;
import static com.google.code.kaptcha.Constants.KAPTCHA_BORDER;
import static com.google.code.kaptcha.Constants.KAPTCHA_BORDER_COLOR;
import static com.google.code.kaptcha.Constants.KAPTCHA_IMAGE_HEIGHT;
import static com.google.code.kaptcha.Constants.KAPTCHA_IMAGE_WIDTH;
import static com.google.code.kaptcha.Constants.KAPTCHA_NOISE_COLOR;
import static com.google.code.kaptcha.Constants.KAPTCHA_NOISE_IMPL;
import static com.google.code.kaptcha.Constants.KAPTCHA_OBSCURIFICATOR_IMPL;
import static com.google.code.kaptcha.Constants.KAPTCHA_SESSION_CONFIG_KEY;
import static com.google.code.kaptcha.Constants.KAPTCHA_TEXTPRODUCER_CHAR_LENGTH;
import static com.google.code.kaptcha.Constants.KAPTCHA_TEXTPRODUCER_CHAR_SPACE;
import static com.google.code.kaptcha.Constants.KAPTCHA_TEXTPRODUCER_FONT_COLOR;
import static com.google.code.kaptcha.Constants.KAPTCHA_TEXTPRODUCER_FONT_NAMES;
import static com.google.code.kaptcha.Constants.KAPTCHA_TEXTPRODUCER_FONT_SIZE;
import static com.google.code.kaptcha.Constants.KAPTCHA_TEXTPRODUCER_IMPL;
/**
 * 验证码配置
 *
 * @author ruoyi
 */
@Configuration
public class CaptchaConfig {
    @Bean(name = "captchaProducer")
    public DefaultKaptcha getKaptchaBean() {
        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
        Properties properties = new Properties();
        properties.setProperty(KAPTCHA_BORDER, "yes");
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black");
        properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
        properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38");
        properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode");
        properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
        properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
        defaultKaptcha.setConfig(new Config(properties));
        return defaultKaptcha;
    }
    @Bean(name = "captchaProducerMath")
    public DefaultKaptcha getKaptchaBeanMath() {
        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
        Properties properties = new Properties();
        properties.setProperty(KAPTCHA_BORDER, "yes");
        properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90");
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue");
        properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
        properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "35");
        properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath");
        properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.xiaopeng.account.config.KaptchaTextCreator");
        properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3");
        properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6");
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
        properties.setProperty(KAPTCHA_NOISE_COLOR, "white");
        properties.setProperty(KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise");
        properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
        defaultKaptcha.setConfig(new Config(properties));
        return defaultKaptcha;
    }
}
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/config/KaptchaTextCreator.java
New file
@@ -0,0 +1,55 @@
package com.xiaopeng.account.config;
import com.google.code.kaptcha.text.impl.DefaultTextCreator;
import java.util.Random;
/**
 * 验证码文本生成器
 *
 * @author ruoyi
 */
public class KaptchaTextCreator extends DefaultTextCreator {
    @Override
    public String getText() {
        int result;
        Random random = new Random();
        int x = random.nextInt(10);
        int y = random.nextInt(10);
        StringBuilder suChinese = new StringBuilder();
        int randomOperator = random.nextInt(3);
        if (randomOperator == 0) {
            result = x * y;
            suChinese.append(x);
            suChinese.append("*");
            suChinese.append(y);
        } else if (randomOperator == 1) {
            if ((x != 0) && (y % x == 0)) {
                result = y / x;
                suChinese.append(y);
                suChinese.append("/");
                suChinese.append(x);
            } else {
                result = x + y;
                suChinese.append(x);
                suChinese.append("+");
                suChinese.append(y);
            }
        } else {
            if (x >= y) {
                result = x - y;
                suChinese.append(x);
                suChinese.append("-");
                suChinese.append(y);
            } else {
                result = y - x;
                suChinese.append(y);
                suChinese.append("-");
                suChinese.append(x);
            }
        }
        suChinese.append("=?@").append(result);
        return suChinese.toString();
    }
}
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/config/properties/CaptchaProperties.java
New file
@@ -0,0 +1,42 @@
package com.xiaopeng.account.config.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Configuration;
/**
 * 验证码配置
 *
 * @author ruoyi
 */
@Configuration
@RefreshScope
@ConfigurationProperties(prefix = "security.captcha")
public class CaptchaProperties {
    /**
     * 验证码开关
     */
    private Boolean enabled;
    /**
     * 验证码类型(math 数组计算 char 字符)
     */
    private String type;
    public Boolean getEnabled() {
        return enabled;
    }
    public void setEnabled(Boolean enabled) {
        this.enabled = enabled;
    }
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
}
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/controller/CaptchaController.java
New file
@@ -0,0 +1,30 @@
package com.xiaopeng.account.controller;
import com.xiaopeng.account.service.IValidateCodeService;
import com.xiaopeng.common.core.exception.CaptchaException;
import com.xiaopeng.common.core.web.domain.AjaxResult;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Lazy;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
/**
 * 图形验证码控制器
 *
 * @author ruoyi
 */
@RestController
@RequiredArgsConstructor(onConstructor_ = @Lazy)
public class CaptchaController {
    private final IValidateCodeService validateCodeService;
    @ApiOperation(value = "获取图形验证码", tags = {"管理后台-用户登录"})
    @GetMapping("/base/v1/captcha")
    public AjaxResult captcha() throws CaptchaException, IOException {
        return validateCodeService.createCaptcha();
    }
}
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/service/IValidateCodeService.java
New file
@@ -0,0 +1,19 @@
package com.xiaopeng.account.service;
import com.xiaopeng.common.core.exception.CaptchaException;
import com.xiaopeng.common.core.web.domain.AjaxResult;
import java.io.IOException;
/**
 * 验证码处理
 *
 * @author ruoyi
 */
public interface IValidateCodeService {
    /**
     * 生成验证码
     */
    AjaxResult createCaptcha() throws IOException, CaptchaException;
}
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/service/impl/ValidateCodeServiceImpl.java
New file
@@ -0,0 +1,84 @@
package com.xiaopeng.account.service.impl;
import com.google.code.kaptcha.Producer;
import com.xiaopeng.account.config.properties.CaptchaProperties;
import com.xiaopeng.account.service.IValidateCodeService;
import com.xiaopeng.common.core.constant.CacheConstants;
import com.xiaopeng.common.core.constant.Constants;
import com.xiaopeng.common.core.exception.CaptchaException;
import com.xiaopeng.common.core.utils.sign.Base64;
import com.xiaopeng.common.core.utils.uuid.IdUtils;
import com.xiaopeng.common.core.web.domain.AjaxResult;
import com.xiaopeng.common.redis.service.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.FastByteArrayOutputStream;
import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
/**
 * 验证码实现处理
 *
 * @author ruoyi
 */
@Service
public class ValidateCodeServiceImpl implements IValidateCodeService {
    @Resource(name = "captchaProducer")
    private Producer captchaProducer;
    @Resource(name = "captchaProducerMath")
    private Producer captchaProducerMath;
    @Autowired
    private RedisService redisService;
    @Autowired
    private CaptchaProperties captchaProperties;
    @Override
    public AjaxResult createCaptcha() throws IOException, CaptchaException {
        AjaxResult ajax = AjaxResult.success();
        boolean captchaEnabled = Boolean.TRUE.equals(captchaProperties.getEnabled());
        ajax.put("captchaEnabled", captchaEnabled);
        if (!captchaEnabled) {
            return ajax;
        }
        String uuid = IdUtils.simpleUUID();
        String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;
        String capStr = null;
        String code = null;
        BufferedImage image = null;
        String captchaType = captchaProperties.getType();
        if ("math".equals(captchaType)) {
            String capText = captchaProducerMath.createText();
            capStr = capText.substring(0, capText.lastIndexOf("@"));
            code = capText.substring(capText.lastIndexOf("@") + 1);
            image = captchaProducerMath.createImage(capStr);
        } else {
            capStr = captchaProducer.createText();
            code = capStr;
            image = captchaProducer.createImage(capStr);
        }
        redisService.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
        FastByteArrayOutputStream os = new FastByteArrayOutputStream();
        try {
            ImageIO.write(image, "jpg", os);
        } catch (IOException e) {
            return AjaxResult.error(e.getMessage());
        }
        ajax.put("uuid", uuid);
        ajax.put("img", Base64.encode(os.toByteArray()));
        return ajax;
    }
}
xp-robotaxi-common/xp-common-security/src/main/java/com/xiaopeng/common/security/config/WebMvcConfig.java
@@ -12,7 +12,18 @@
public class WebMvcConfig implements WebMvcConfigurer
{
    /** 不需要拦截地址 */
    public static final String[] excludeUrls = { "/login", "/logout", "/refresh" };
    public static final String[] excludeUrls = {
            "/login",
            "/logout",
            "/refresh",
            "/register",
            "/base/v1/login",
            "/base/v1/captcha",
            "/base/v1/operationPasswordLogin",
            "/base/v1/verificationCodeLogin",
            "/base/v1/getVerificationCode",
            "/base/v1/updatePassword"
    };
    @Override
    public void addInterceptors(InterceptorRegistry registry)
xp-robotaxi-gateway-boot/src/main/java/com/xiaopeng/gateway/config/CaptchaConfig.java
File was deleted
xp-robotaxi-gateway-boot/src/main/java/com/xiaopeng/gateway/config/KaptchaTextCreator.java
File was deleted
xp-robotaxi-gateway-boot/src/main/java/com/xiaopeng/gateway/config/RouterFunctionConfiguration.java
@@ -1,19 +1,13 @@
package com.xiaopeng.gateway.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import com.xiaopeng.gateway.handler.ValidateCodeHandler;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
@@ -35,17 +29,6 @@
    private static final String ALLOWED_ORIGIN = "*";
    private static final String ALLOWED_EXPOSE = "*";
    private static final String MAX_AGE = "18000L";
    @Autowired
    private ValidateCodeHandler validateCodeHandler;
    @SuppressWarnings("rawtypes")
    @Bean
    public RouterFunction routerFunction() {
        return RouterFunctions.route(
                RequestPredicates.GET("/code").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)),
                validateCodeHandler);
    }
    /**
     * 跨域配置
xp-robotaxi-gateway-boot/src/main/java/com/xiaopeng/gateway/handler/ValidateCodeHandler.java
File was deleted
xp-robotaxi-gateway-boot/src/main/java/com/xiaopeng/gateway/service/ValidateCodeService.java
@@ -1,9 +1,6 @@
package com.xiaopeng.gateway.service;
import java.io.IOException;
import com.xiaopeng.common.core.exception.CaptchaException;
import com.xiaopeng.common.core.web.domain.AjaxResult;
/**
 * 验证码处理
@@ -11,11 +8,6 @@
 * @author ruoyi
 */
public interface ValidateCodeService {
    /**
     * 生成验证码
     */
    public AjaxResult createCaptcha() throws IOException, CaptchaException;
    /**
     * 校验验证码
     */
xp-robotaxi-gateway-boot/src/main/java/com/xiaopeng/gateway/service/impl/ValidateCodeServiceImpl.java
@@ -1,24 +1,11 @@
package com.xiaopeng.gateway.service.impl;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import javax.imageio.ImageIO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.FastByteArrayOutputStream;
import com.google.code.kaptcha.Producer;
import com.xiaopeng.common.core.constant.CacheConstants;
import com.xiaopeng.common.core.constant.Constants;
import com.xiaopeng.common.core.exception.CaptchaException;
import com.xiaopeng.common.core.utils.StringUtils;
import com.xiaopeng.common.core.utils.sign.Base64;
import com.xiaopeng.common.core.utils.uuid.IdUtils;
import com.xiaopeng.common.core.web.domain.AjaxResult;
import com.xiaopeng.common.redis.service.RedisService;
import com.xiaopeng.gateway.config.properties.CaptchaProperties;
import com.xiaopeng.gateway.service.ValidateCodeService;
/**
@@ -28,62 +15,9 @@
 */
@Service
public class ValidateCodeServiceImpl implements ValidateCodeService {
    @Resource(name = "captchaProducer")
    private Producer captchaProducer;
    @Resource(name = "captchaProducerMath")
    private Producer captchaProducerMath;
    @Autowired
    private RedisService redisService;
    @Autowired
    private CaptchaProperties captchaProperties;
    /**
     * 生成验证码
     */
    @Override
    public AjaxResult createCaptcha() throws IOException, CaptchaException {
        AjaxResult ajax = AjaxResult.success();
        boolean captchaEnabled = captchaProperties.getEnabled();
        ajax.put("captchaEnabled", captchaEnabled);
        if (!captchaEnabled) {
            return ajax;
        }
        // 保存验证码信息
        String uuid = IdUtils.simpleUUID();
        String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;
        String capStr = null, code = null;
        BufferedImage image = null;
        String captchaType = captchaProperties.getType();
        // 生成验证码
        if ("math".equals(captchaType)) {
            String capText = captchaProducerMath.createText();
            capStr = capText.substring(0, capText.lastIndexOf("@"));
            code = capText.substring(capText.lastIndexOf("@") + 1);
            image = captchaProducerMath.createImage(capStr);
        } else if ("char".equals(captchaType)) {
            capStr = code = captchaProducer.createText();
            image = captchaProducer.createImage(capStr);
        }
        redisService.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
        // 转换流信息写出
        FastByteArrayOutputStream os = new FastByteArrayOutputStream();
        try {
            ImageIO.write(image, "jpg", os);
        } catch (IOException e) {
            return AjaxResult.error(e.getMessage());
        }
        ajax.put("uuid", uuid);
        ajax.put("img", Base64.encode(os.toByteArray()));
        return ajax;
    }
    
    /**
     * 校验验证码