mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-11-04 12:18:42 +08:00 
			
		
		
		
	优化图片验证码的后端实现
This commit is contained in:
		@@ -33,8 +33,10 @@ public class AuthLoginReqVO {
 | 
			
		||||
    @Length(min = 4, max = 16, message = "密码长度为 4-16 位")
 | 
			
		||||
    private String password;
 | 
			
		||||
 | 
			
		||||
    @ApiModelProperty(value = "验证码", required = true, example = "PfcH6mgr8tpXuMWFjvW6YVaqrswIuwmWI5dsVZSg7sGpWtDCUbHuDEXl3cFB1+VvCC/rAkSwK8Fad52FSuncVg==")
 | 
			
		||||
    @NotEmpty(message = "验证码不能为空")
 | 
			
		||||
    @ApiModelProperty(value = "验证码", required = true,
 | 
			
		||||
            example = "PfcH6mgr8tpXuMWFjvW6YVaqrswIuwmWI5dsVZSg7sGpWtDCUbHuDEXl3cFB1+VvCC/rAkSwK8Fad52FSuncVg==",
 | 
			
		||||
            notes = "验证码开启时,需要传递")
 | 
			
		||||
    @NotEmpty(message = "验证码不能为空", groups = CodeEnableGroup.class)
 | 
			
		||||
    private String captchaVerification;
 | 
			
		||||
 | 
			
		||||
    // ========== 绑定社交登录时,需要传递如下参数 ==========
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.framework.captcha.config;
 | 
			
		||||
 | 
			
		||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
 | 
			
		||||
import org.springframework.context.annotation.Configuration;
 | 
			
		||||
 | 
			
		||||
@Configuration
 | 
			
		||||
@EnableConfigurationProperties(CaptchaProperties.class)
 | 
			
		||||
public class CaptchaConfig {
 | 
			
		||||
}
 | 
			
		||||
@@ -1,38 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.framework.captcha.config;
 | 
			
		||||
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import org.springframework.boot.context.properties.ConfigurationProperties;
 | 
			
		||||
import org.springframework.validation.annotation.Validated;
 | 
			
		||||
 | 
			
		||||
import javax.validation.constraints.NotNull;
 | 
			
		||||
import java.time.Duration;
 | 
			
		||||
 | 
			
		||||
@ConfigurationProperties(prefix = "yudao.captcha")
 | 
			
		||||
@Validated
 | 
			
		||||
@Data
 | 
			
		||||
public class CaptchaProperties {
 | 
			
		||||
 | 
			
		||||
    private static final Boolean ENABLE_DEFAULT = true;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否开启
 | 
			
		||||
     * 注意,这里仅仅是后端 Server 是否校验,暂时不控制前端的逻辑
 | 
			
		||||
     */
 | 
			
		||||
    private Boolean enable = ENABLE_DEFAULT;
 | 
			
		||||
    /**
 | 
			
		||||
     * 验证码的过期时间
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull(message = "验证码的过期时间不为空")
 | 
			
		||||
    private Duration timeout;
 | 
			
		||||
    /**
 | 
			
		||||
     * 验证码的高度
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull(message = "验证码的高度不能为空")
 | 
			
		||||
    private Integer height;
 | 
			
		||||
    /**
 | 
			
		||||
     * 验证码的宽度
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull(message = "验证码的宽度不能为空")
 | 
			
		||||
    private Integer width;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +0,0 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 基于 Hutool captcha 库,实现验证码功能
 | 
			
		||||
 */
 | 
			
		||||
package cn.iocoder.yudao.module.system.framework.captcha;
 | 
			
		||||
@@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
 | 
			
		||||
@@ -24,7 +25,9 @@ import cn.iocoder.yudao.module.system.service.user.AdminUserService;
 | 
			
		||||
import com.anji.captcha.model.common.ResponseModel;
 | 
			
		||||
import com.anji.captcha.model.vo.CaptchaVO;
 | 
			
		||||
import com.anji.captcha.service.CaptchaService;
 | 
			
		||||
import com.google.common.annotations.VisibleForTesting;
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Value;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Resource;
 | 
			
		||||
@@ -61,6 +64,12 @@ public class AdminAuthServiceImpl implements AdminAuthService {
 | 
			
		||||
    @Resource
 | 
			
		||||
    private SmsCodeApi smsCodeApi;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 验证码的开关,默认为 true
 | 
			
		||||
     */
 | 
			
		||||
    @Value("${yudao.captcha.enable:true}")
 | 
			
		||||
    private Boolean captchaEnable;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public AdminUserDO authenticate(String username, String password) {
 | 
			
		||||
        final LoginLogTypeEnum logTypeEnum = LoginLogTypeEnum.LOGIN_USERNAME;
 | 
			
		||||
@@ -84,23 +93,19 @@ public class AdminAuthServiceImpl implements AdminAuthService {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public AuthLoginRespVO login(AuthLoginReqVO reqVO) {
 | 
			
		||||
        CaptchaVO captchaVO = new CaptchaVO();
 | 
			
		||||
        captchaVO.setCaptchaVerification(reqVO.getCaptchaVerification());
 | 
			
		||||
        ResponseModel response = captchaService.verification(captchaVO);
 | 
			
		||||
        if(response.isSuccess()){
 | 
			
		||||
            // 使用账号密码,进行登录
 | 
			
		||||
            AdminUserDO user = authenticate(reqVO.getUsername(), reqVO.getPassword());
 | 
			
		||||
        // 校验验证码
 | 
			
		||||
        verifyCaptcha(reqVO);
 | 
			
		||||
 | 
			
		||||
            // 如果 socialType 非空,说明需要绑定社交用户
 | 
			
		||||
            if (reqVO.getSocialType() != null) {
 | 
			
		||||
                socialUserService.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(),
 | 
			
		||||
                        reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState()));
 | 
			
		||||
            }
 | 
			
		||||
            // 创建 Token 令牌,记录登录日志
 | 
			
		||||
            return createTokenAfterLoginSuccess(user.getId(), reqVO.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME);
 | 
			
		||||
        }else{
 | 
			
		||||
            throw exception(AUTH_LOGIN_CAPTCHA_CODE_ERROR);
 | 
			
		||||
        // 使用账号密码,进行登录
 | 
			
		||||
        AdminUserDO user = authenticate(reqVO.getUsername(), reqVO.getPassword());
 | 
			
		||||
 | 
			
		||||
        // 如果 socialType 非空,说明需要绑定社交用户
 | 
			
		||||
        if (reqVO.getSocialType() != null) {
 | 
			
		||||
            socialUserService.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(),
 | 
			
		||||
                    reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState()));
 | 
			
		||||
        }
 | 
			
		||||
        // 创建 Token 令牌,记录登录日志
 | 
			
		||||
        return createTokenAfterLoginSuccess(user.getId(), reqVO.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
@@ -172,6 +177,25 @@ public class AdminAuthServiceImpl implements AdminAuthService {
 | 
			
		||||
        return AuthConvert.INSTANCE.convert(accessTokenDO);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @VisibleForTesting
 | 
			
		||||
    void verifyCaptcha(AuthLoginReqVO reqVO) {
 | 
			
		||||
        // 如果验证码关闭,则不进行校验
 | 
			
		||||
        if (!captchaEnable) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        // 校验验证码
 | 
			
		||||
        ValidationUtils.validate(validator, reqVO, AuthLoginReqVO.CodeEnableGroup.class);
 | 
			
		||||
        CaptchaVO captchaVO = new CaptchaVO();
 | 
			
		||||
        captchaVO.setCaptchaVerification(reqVO.getCaptchaVerification());
 | 
			
		||||
        ResponseModel response = captchaService.verification(captchaVO);
 | 
			
		||||
        // 验证不通过
 | 
			
		||||
        if (!response.isSuccess()) {
 | 
			
		||||
            // 创建登录失败日志(验证码不正确)
 | 
			
		||||
            createLoginLog(null, reqVO.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME, LoginResultEnum.CAPTCHA_CODE_ERROR);
 | 
			
		||||
            throw exception(AUTH_LOGIN_CAPTCHA_CODE_ERROR, response.getRepMsg());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private AuthLoginRespVO createTokenAfterLoginSuccess(Long userId, String username, LoginLogTypeEnum logType) {
 | 
			
		||||
        // 插入登陆日志
 | 
			
		||||
        createLoginLog(userId, username, logType, LoginResultEnum.SUCCESS);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user