mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-11-04 20:28:44 +08:00 
			
		
		
		
	@@ -55,7 +55,6 @@ public class AuthController {
 | 
			
		||||
    private PermissionService permissionService;
 | 
			
		||||
    @Resource
 | 
			
		||||
    private SocialUserService socialUserService;
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private SecurityProperties securityProperties;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -35,13 +35,11 @@ public class AuthLoginReqVO {
 | 
			
		||||
 | 
			
		||||
    // ========== 图片验证码相关 ==========
 | 
			
		||||
 | 
			
		||||
    @ApiModelProperty(value = "验证码", required = true, example = "1024", notes = "验证码开启时,需要传递")
 | 
			
		||||
    @ApiModelProperty(value = "验证码", required = true,
 | 
			
		||||
            example = "PfcH6mgr8tpXuMWFjvW6YVaqrswIuwmWI5dsVZSg7sGpWtDCUbHuDEXl3cFB1+VvCC/rAkSwK8Fad52FSuncVg==",
 | 
			
		||||
            notes = "验证码开启时,需要传递")
 | 
			
		||||
    @NotEmpty(message = "验证码不能为空", groups = CodeEnableGroup.class)
 | 
			
		||||
    private String code;
 | 
			
		||||
 | 
			
		||||
    @ApiModelProperty(value = "验证码的唯一标识", required = true, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62", notes = "验证码开启时,需要传递")
 | 
			
		||||
    @NotEmpty(message = "唯一标识不能为空", groups = CodeEnableGroup.class)
 | 
			
		||||
    private String uuid;
 | 
			
		||||
    private String captchaVerification;
 | 
			
		||||
 | 
			
		||||
    // ========== 绑定社交登录时,需要传递如下参数 ==========
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +0,0 @@
 | 
			
		||||
### 请求 /captcha/get-image 接口 => 成功
 | 
			
		||||
GET {{baseUrl}}/system/captcha/get-image
 | 
			
		||||
tenant-id: {{adminTenentId}}
 | 
			
		||||
@@ -1,32 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.controller.admin.common;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 | 
			
		||||
import cn.iocoder.yudao.module.system.controller.admin.common.vo.CaptchaImageRespVO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.service.common.CaptchaService;
 | 
			
		||||
import io.swagger.annotations.Api;
 | 
			
		||||
import io.swagger.annotations.ApiOperation;
 | 
			
		||||
import org.springframework.web.bind.annotation.GetMapping;
 | 
			
		||||
import org.springframework.web.bind.annotation.RequestMapping;
 | 
			
		||||
import org.springframework.web.bind.annotation.RestController;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Resource;
 | 
			
		||||
import javax.annotation.security.PermitAll;
 | 
			
		||||
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 | 
			
		||||
 | 
			
		||||
@Api(tags = "管理后台 - 验证码")
 | 
			
		||||
@RestController
 | 
			
		||||
@RequestMapping("/system/captcha")
 | 
			
		||||
public class CaptchaController {
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private CaptchaService captchaService;
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/get-image")
 | 
			
		||||
    @PermitAll
 | 
			
		||||
    @ApiOperation("生成图片验证码")
 | 
			
		||||
    public CommonResult<CaptchaImageRespVO> getCaptchaImage() {
 | 
			
		||||
        return success(captchaService.getCaptchaImage());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,27 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.controller.admin.common.vo;
 | 
			
		||||
 | 
			
		||||
import io.swagger.annotations.ApiModel;
 | 
			
		||||
import io.swagger.annotations.ApiModelProperty;
 | 
			
		||||
import lombok.AllArgsConstructor;
 | 
			
		||||
import lombok.Builder;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.NoArgsConstructor;
 | 
			
		||||
 | 
			
		||||
@ApiModel("管理后台 - 验证码图片 Response VO")
 | 
			
		||||
@Data
 | 
			
		||||
@Builder
 | 
			
		||||
@NoArgsConstructor
 | 
			
		||||
@AllArgsConstructor
 | 
			
		||||
public class CaptchaImageRespVO {
 | 
			
		||||
 | 
			
		||||
    @ApiModelProperty(value = "是否开启", required = true, example = "true", notes = "如果为 false,则关闭验证码功能")
 | 
			
		||||
    private Boolean enable;
 | 
			
		||||
 | 
			
		||||
    @ApiModelProperty(value = "uuid", example = "1b3b7d00-83a8-4638-9e37-d67011855968",
 | 
			
		||||
            notes = "enable = true 时,非空!通过该 uuid 作为该验证码的标识")
 | 
			
		||||
    private String uuid;
 | 
			
		||||
 | 
			
		||||
    @ApiModelProperty(value = "图片", notes = "enable = true 时,非空!验证码的图片内容,使用 Base64 编码")
 | 
			
		||||
    private String img;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,17 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.convert.common;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.captcha.AbstractCaptcha;
 | 
			
		||||
import cn.iocoder.yudao.module.system.controller.admin.common.vo.CaptchaImageRespVO;
 | 
			
		||||
import org.mapstruct.Mapper;
 | 
			
		||||
import org.mapstruct.factory.Mappers;
 | 
			
		||||
 | 
			
		||||
@Mapper
 | 
			
		||||
public interface CaptchaConvert {
 | 
			
		||||
 | 
			
		||||
    CaptchaConvert INSTANCE = Mappers.getMapper(CaptchaConvert.class);
 | 
			
		||||
 | 
			
		||||
    default CaptchaImageRespVO convert(String uuid, AbstractCaptcha captcha) {
 | 
			
		||||
        return CaptchaImageRespVO.builder().uuid(uuid).img(captcha.getImageBase64()).build();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -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;
 | 
			
		||||
@@ -17,14 +17,17 @@ import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum;
 | 
			
		||||
import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum;
 | 
			
		||||
import cn.iocoder.yudao.module.system.enums.oauth2.OAuth2ClientConstants;
 | 
			
		||||
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
 | 
			
		||||
import cn.iocoder.yudao.module.system.service.common.CaptchaService;
 | 
			
		||||
import cn.iocoder.yudao.module.system.service.logger.LoginLogService;
 | 
			
		||||
import cn.iocoder.yudao.module.system.service.member.MemberService;
 | 
			
		||||
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService;
 | 
			
		||||
import cn.iocoder.yudao.module.system.service.social.SocialUserService;
 | 
			
		||||
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;
 | 
			
		||||
@@ -47,8 +50,6 @@ public class AdminAuthServiceImpl implements AdminAuthService {
 | 
			
		||||
    @Resource
 | 
			
		||||
    private AdminUserService userService;
 | 
			
		||||
    @Resource
 | 
			
		||||
    private CaptchaService captchaService;
 | 
			
		||||
    @Resource
 | 
			
		||||
    private LoginLogService loginLogService;
 | 
			
		||||
    @Resource
 | 
			
		||||
    private OAuth2TokenService oauth2TokenService;
 | 
			
		||||
@@ -56,13 +57,19 @@ public class AdminAuthServiceImpl implements AdminAuthService {
 | 
			
		||||
    private SocialUserService socialUserService;
 | 
			
		||||
    @Resource
 | 
			
		||||
    private MemberService memberService;
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private Validator validator;
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private CaptchaService captchaService;
 | 
			
		||||
    @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;
 | 
			
		||||
@@ -86,7 +93,7 @@ public class AdminAuthServiceImpl implements AdminAuthService {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public AuthLoginRespVO login(AuthLoginReqVO reqVO) {
 | 
			
		||||
        // 判断验证码是否正确
 | 
			
		||||
        // 校验验证码
 | 
			
		||||
        verifyCaptcha(reqVO);
 | 
			
		||||
 | 
			
		||||
        // 使用账号密码,进行登录
 | 
			
		||||
@@ -97,7 +104,6 @@ public class AdminAuthServiceImpl implements AdminAuthService {
 | 
			
		||||
            socialUserService.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(),
 | 
			
		||||
                    reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState()));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 创建 Token 令牌,记录登录日志
 | 
			
		||||
        return createTokenAfterLoginSuccess(user.getId(), reqVO.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME);
 | 
			
		||||
    }
 | 
			
		||||
@@ -127,32 +133,6 @@ public class AdminAuthServiceImpl implements AdminAuthService {
 | 
			
		||||
        return createTokenAfterLoginSuccess(user.getId(), reqVO.getMobile(), LoginLogTypeEnum.LOGIN_MOBILE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @VisibleForTesting
 | 
			
		||||
    void verifyCaptcha(AuthLoginReqVO reqVO) {
 | 
			
		||||
        // 如果验证码关闭,则不进行校验
 | 
			
		||||
        if (!captchaService.isCaptchaEnable()) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        // 校验验证码
 | 
			
		||||
        ValidationUtils.validate(validator, reqVO, AuthLoginReqVO.CodeEnableGroup.class);
 | 
			
		||||
        // 验证码不存在
 | 
			
		||||
        final LoginLogTypeEnum logTypeEnum = LoginLogTypeEnum.LOGIN_USERNAME;
 | 
			
		||||
        String code = captchaService.getCaptchaCode(reqVO.getUuid());
 | 
			
		||||
        if (code == null) {
 | 
			
		||||
            // 创建登录失败日志(验证码不存在)
 | 
			
		||||
            createLoginLog(null, reqVO.getUsername(), logTypeEnum, LoginResultEnum.CAPTCHA_NOT_FOUND);
 | 
			
		||||
            throw exception(AUTH_LOGIN_CAPTCHA_NOT_FOUND);
 | 
			
		||||
        }
 | 
			
		||||
        // 验证码不正确
 | 
			
		||||
        if (!code.equals(reqVO.getCode())) {
 | 
			
		||||
            // 创建登录失败日志(验证码不正确)
 | 
			
		||||
            createLoginLog(null, reqVO.getUsername(), logTypeEnum, LoginResultEnum.CAPTCHA_CODE_ERROR);
 | 
			
		||||
            throw exception(AUTH_LOGIN_CAPTCHA_CODE_ERROR);
 | 
			
		||||
        }
 | 
			
		||||
        // 正确,所以要删除下验证码
 | 
			
		||||
        captchaService.deleteCaptchaCode(reqVO.getUuid());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void createLoginLog(Long userId, String username,
 | 
			
		||||
                                LoginLogTypeEnum logTypeEnum, LoginResultEnum loginResult) {
 | 
			
		||||
        // 插入登录日志
 | 
			
		||||
@@ -197,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);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,39 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.service.common;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.module.system.controller.admin.common.vo.CaptchaImageRespVO;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 验证码 Service 接口
 | 
			
		||||
 */
 | 
			
		||||
public interface CaptchaService {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获得验证码图片
 | 
			
		||||
     *
 | 
			
		||||
     * @return 验证码图片
 | 
			
		||||
     */
 | 
			
		||||
    CaptchaImageRespVO getCaptchaImage();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否开启图片验证码
 | 
			
		||||
     *
 | 
			
		||||
     * @return 是否
 | 
			
		||||
     */
 | 
			
		||||
    Boolean isCaptchaEnable();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获得 uuid 对应的验证码
 | 
			
		||||
     *
 | 
			
		||||
     * @param uuid 验证码编号
 | 
			
		||||
     * @return 验证码
 | 
			
		||||
     */
 | 
			
		||||
    String getCaptchaCode(String uuid);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 删除 uuid 对应的验证码
 | 
			
		||||
     *
 | 
			
		||||
     * @param uuid 验证码编号
 | 
			
		||||
     */
 | 
			
		||||
    void deleteCaptchaCode(String uuid);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,65 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.service.common;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.captcha.CaptchaUtil;
 | 
			
		||||
import cn.hutool.captcha.CircleCaptcha;
 | 
			
		||||
import cn.hutool.core.util.IdUtil;
 | 
			
		||||
import cn.iocoder.yudao.module.system.convert.common.CaptchaConvert;
 | 
			
		||||
import cn.iocoder.yudao.module.system.framework.captcha.config.CaptchaProperties;
 | 
			
		||||
import cn.iocoder.yudao.module.system.controller.admin.common.vo.CaptchaImageRespVO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.redis.common.CaptchaRedisDAO;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Value;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Resource;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 验证码 Service 实现类
 | 
			
		||||
 */
 | 
			
		||||
@Service
 | 
			
		||||
public class CaptchaServiceImpl implements CaptchaService {
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private CaptchaProperties captchaProperties;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 验证码是否开关
 | 
			
		||||
     *
 | 
			
		||||
     * 虽然 {@link CaptchaProperties#getEnable()} 有该属性,但是 Apollo 在 Spring Boot 下无法刷新 @ConfigurationProperties 注解,
 | 
			
		||||
     * 所以暂时只能这么处理~
 | 
			
		||||
     */
 | 
			
		||||
    @Value("${yudao.captcha.enable}")
 | 
			
		||||
    private Boolean enable;
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private CaptchaRedisDAO captchaRedisDAO;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public CaptchaImageRespVO getCaptchaImage() {
 | 
			
		||||
        if (!Boolean.TRUE.equals(enable)) {
 | 
			
		||||
            return CaptchaImageRespVO.builder().enable(enable).build();
 | 
			
		||||
        }
 | 
			
		||||
        // 生成验证码
 | 
			
		||||
        CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(captchaProperties.getWidth(), captchaProperties.getHeight());
 | 
			
		||||
        // 缓存到 Redis 中
 | 
			
		||||
        String uuid = IdUtil.fastSimpleUUID();
 | 
			
		||||
        captchaRedisDAO.set(uuid, captcha.getCode(), captchaProperties.getTimeout());
 | 
			
		||||
        // 返回
 | 
			
		||||
        return CaptchaConvert.INSTANCE.convert(uuid, captcha).setEnable(enable);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Boolean isCaptchaEnable() {
 | 
			
		||||
        return enable;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getCaptchaCode(String uuid) {
 | 
			
		||||
        return captchaRedisDAO.get(uuid);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void deleteCaptchaCode(String uuid) {
 | 
			
		||||
        captchaRedisDAO.delete(uuid);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user