feat: 整合滑动图像验证码完成
This commit is contained in:
@@ -41,6 +41,6 @@ public class GlobalConfig extends WebMvcConfigurationSupport {
|
||||
@Override
|
||||
protected void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(new LoginInterceptor())
|
||||
.addPathPatterns("/**").excludePathPatterns("/oauth/**","/system/**","/user/**","/ReactRotateCaptcha/**","/sms/**");
|
||||
.addPathPatterns("/**").excludePathPatterns("/oauth/**","/system/**","/auth/**","/ReactRotateCaptcha/**","/sms/sendByTemplate");
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,8 @@
|
||||
package com.schisandra.auth.application.controller;
|
||||
|
||||
import cn.dev33.satoken.secure.SaSecureUtil;
|
||||
import cn.hutool.core.lang.UUID;
|
||||
import cn.hutool.core.lang.generator.UUIDGenerator;
|
||||
import com.schisandra.auth.application.dto.SchisandraCaptchaDTO;
|
||||
import com.schisandra.auth.common.entity.CaptchaResult;
|
||||
import com.schisandra.auth.common.redis.RedisUtil;
|
||||
@@ -28,10 +30,8 @@ public class ReactRotateCaptchaController {
|
||||
@Resource
|
||||
private RedisUtil redisUtil;
|
||||
|
||||
public final String authRotateCaptchaPrefix = "auth.RotateCaptcha";
|
||||
public final String authRotateCaptchaPrefix = "auth.rotate.captcha";
|
||||
|
||||
@Value("${cipher.salt}")
|
||||
private String salt;
|
||||
|
||||
/**
|
||||
* @description: 获取图片
|
||||
@@ -50,7 +50,7 @@ public class ReactRotateCaptchaController {
|
||||
double randomNumber = random.nextInt(280) + 40;
|
||||
InputStream inputStream = ReactRotateCaptchaController.class.getClassLoader().getResourceAsStream("image/test1.jpg");
|
||||
BufferedImage image = ImageIO.read(inputStream);
|
||||
String token = SaSecureUtil.md5BySalt(String.valueOf(randomNumber), salt);
|
||||
String token = UUID.randomUUID().toString();
|
||||
String prefix = redisUtil.buildKey(authRotateCaptchaPrefix, token);
|
||||
redisUtil.setNx(prefix, String.valueOf(randomNumber), 60L, TimeUnit.SECONDS);
|
||||
BufferedImage image1 = rotateImageUtils.rotateImage(image, randomNumber, Color.black);
|
||||
|
@@ -5,6 +5,8 @@ import com.alibaba.fastjson.JSON;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.schisandra.auth.application.convert.SchisandraAuthUserDTOConverter;
|
||||
import com.schisandra.auth.application.dto.SchisandraAuthUserDTO;
|
||||
import com.schisandra.auth.application.utils.CheckRouteCaptcha;
|
||||
import com.schisandra.auth.common.entity.CaptchaResult;
|
||||
import com.schisandra.auth.common.entity.Result;
|
||||
import com.schisandra.auth.common.redis.RedisUtil;
|
||||
import com.schisandra.auth.domain.bo.SchisandraAuthUserBO;
|
||||
@@ -38,6 +40,9 @@ public class SchisandraAuthUserController {
|
||||
|
||||
private final String AUTH_PHONE_PREFIX = "auth.phone";
|
||||
|
||||
@Resource
|
||||
CheckRouteCaptcha checkRouteCaptcha;
|
||||
|
||||
/**
|
||||
* @description: 注册
|
||||
* @param: [schisandraAuthUserDTO]
|
||||
@@ -46,7 +51,7 @@ public class SchisandraAuthUserController {
|
||||
* @date: 2024/5/26 17:23
|
||||
*/
|
||||
@PostMapping("register")
|
||||
public Result register(@RequestBody SchisandraAuthUserDTO schisandraAuthUserDTO) {
|
||||
public CaptchaResult register(@RequestBody SchisandraAuthUserDTO schisandraAuthUserDTO) {
|
||||
if (log.isInfoEnabled()) {
|
||||
log.info("UserController.register.dto:{}", JSON.toJSONString(schisandraAuthUserDTO));
|
||||
}
|
||||
@@ -54,32 +59,39 @@ public class SchisandraAuthUserController {
|
||||
log.error("UserController.register.phone is null");
|
||||
return null;
|
||||
}
|
||||
SchisandraAuthUser schisandraAuthUser = schisandraAuthUserDomainService.queryByPhone(schisandraAuthUserDTO.getPhone());
|
||||
if (ObjectUtils.isNotEmpty(schisandraAuthUser)) {
|
||||
return Result.fail("该手机号已注册");
|
||||
} else {
|
||||
String key = redisUtil.buildKey(AUTH_PHONE_PREFIX, schisandraAuthUserDTO.getPhone());
|
||||
if (redisUtil.exist(key)) {
|
||||
if (!Objects.equals(redisUtil.get(key), schisandraAuthUserDTO.getActiveCode())) {
|
||||
return Result.fail("验证码错误,请重新验证");
|
||||
}
|
||||
try {
|
||||
SchisandraAuthUserBO authUserBO = SchisandraAuthUserDTOConverter.INSTANCE.convertDTOToBO(schisandraAuthUserDTO);
|
||||
if (schisandraAuthUserDomainService.register(authUserBO)) {
|
||||
return Result.ok("注册成功");
|
||||
} else {
|
||||
return Result.fail("注册失败");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("UserController.register.error:{}", e.getMessage(), e);
|
||||
return Result.fail("注册用户失败");
|
||||
}
|
||||
String token = schisandraAuthUserDTO.getToken();
|
||||
Double deg = schisandraAuthUserDTO.getDeg();
|
||||
CaptchaResult captchaResult = checkRouteCaptcha.checkCaptcha(token, deg);
|
||||
if (captchaResult.getCode() == 0) {
|
||||
SchisandraAuthUser schisandraAuthUser = schisandraAuthUserDomainService.queryByPhone(schisandraAuthUserDTO.getPhone());
|
||||
if (ObjectUtils.isNotEmpty(schisandraAuthUser)) {
|
||||
return CaptchaResult.failWithCode("该手机号已注册");
|
||||
} else {
|
||||
return Result.fail("验证码错误,请重新验证");
|
||||
String key = redisUtil.buildKey(AUTH_PHONE_PREFIX, schisandraAuthUserDTO.getPhone());
|
||||
if (redisUtil.exist(key)) {
|
||||
if (!Objects.equals(redisUtil.get(key), schisandraAuthUserDTO.getActiveCode())) {
|
||||
return CaptchaResult.failWithCode("验证码错误,请重新验证");
|
||||
}
|
||||
try {
|
||||
SchisandraAuthUserBO authUserBO = SchisandraAuthUserDTOConverter.INSTANCE.convertDTOToBO(schisandraAuthUserDTO);
|
||||
if (schisandraAuthUserDomainService.register(authUserBO)) {
|
||||
return CaptchaResult.ok("注册成功");
|
||||
} else {
|
||||
return CaptchaResult.failWithCode("注册失败");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("UserController.register.error:{}", e.getMessage(), e);
|
||||
return CaptchaResult.failWithCode("注册用户失败");
|
||||
}
|
||||
} else {
|
||||
return CaptchaResult.failWithCode("验证码错误,请重新验证");
|
||||
}
|
||||
}
|
||||
}else{
|
||||
return CaptchaResult.fail();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 用户登录
|
||||
* @param: [schisandraAuthUserDTO]
|
||||
@@ -88,25 +100,37 @@ public class SchisandraAuthUserController {
|
||||
* @date: 2024/5/31 1:19
|
||||
*/
|
||||
@PostMapping("login")
|
||||
public Result login(@RequestBody SchisandraAuthUserDTO schisandraAuthUserDTO) {
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
SchisandraAuthUserBO schisandraAuthUserBO=SchisandraAuthUserDTOConverter.INSTANCE.convertDTOToBO(schisandraAuthUserDTO);
|
||||
SchisandraAuthUserDTO result=SchisandraAuthUserDTOConverter.INSTANCE.convertBOToDTO(schisandraAuthUserDomainService.login(schisandraAuthUserBO));
|
||||
map.put("user",result);
|
||||
if(result!=null){
|
||||
if (StpUtil.isLogin(result.getId())){
|
||||
StpUtil.logout(result.getId());
|
||||
StpUtil.login(result.getId());
|
||||
String token=StpUtil.getTokenValueByLoginId(result.getId());
|
||||
map.put("token",token);
|
||||
return Result.ok(map);
|
||||
}else {
|
||||
StpUtil.login(result.getId());
|
||||
return Result.ok(result);
|
||||
}
|
||||
}else{
|
||||
return Result.fail("用户名或密码错误");}
|
||||
public CaptchaResult login(@RequestBody SchisandraAuthUserDTO schisandraAuthUserDTO) {
|
||||
|
||||
if (schisandraAuthUserDTO.getDeg() == null && schisandraAuthUserDTO.getToken() == null) {
|
||||
return CaptchaResult.fail("验证失败!");
|
||||
}
|
||||
String token = schisandraAuthUserDTO.getToken();
|
||||
Double deg = schisandraAuthUserDTO.getDeg();
|
||||
CaptchaResult captchaResult = checkRouteCaptcha.checkCaptcha(token, deg);
|
||||
if (captchaResult.getCode() == 0) {
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
SchisandraAuthUserBO schisandraAuthUserBO = SchisandraAuthUserDTOConverter.INSTANCE.convertDTOToBO(schisandraAuthUserDTO);
|
||||
SchisandraAuthUserBO login = schisandraAuthUserDomainService.login(schisandraAuthUserBO);
|
||||
SchisandraAuthUserDTO result = SchisandraAuthUserDTOConverter.INSTANCE.convertBOToDTO(login);
|
||||
map.put("user", result);
|
||||
if (login != null) {
|
||||
if (StpUtil.isLogin(result.getId())) {
|
||||
StpUtil.logout(result.getId());
|
||||
StpUtil.login(result.getId());
|
||||
String userToken = StpUtil.getTokenValueByLoginId(result.getId());
|
||||
map.put("token", userToken);
|
||||
return CaptchaResult.ok(map);
|
||||
} else {
|
||||
StpUtil.login(result.getId());
|
||||
return CaptchaResult.ok(result);
|
||||
}
|
||||
} else {
|
||||
return CaptchaResult.failWithCode();
|
||||
}
|
||||
} else {
|
||||
return CaptchaResult.fail();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -2,14 +2,18 @@ package com.schisandra.auth.application.controller;
|
||||
|
||||
|
||||
import com.schisandra.auth.application.context.SmsConfigContext;
|
||||
import com.schisandra.auth.common.entity.Result;
|
||||
import com.schisandra.auth.application.dto.SchisandraCaptchaDTO;
|
||||
import com.schisandra.auth.application.utils.CheckRouteCaptcha;
|
||||
import com.schisandra.auth.common.entity.CaptchaResult;
|
||||
import com.schisandra.auth.common.redis.RedisUtil;
|
||||
import com.schisandra.auth.common.utils.SmsCodeUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.sms4j.api.entity.SmsResponse;
|
||||
import org.dromara.sms4j.comm.utils.SmsUtils;
|
||||
import org.dromara.sms4j.core.factory.SmsFactory;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@@ -25,6 +29,9 @@ public class SchisandraSmsController {
|
||||
private final String AUTH_PHONE_PREFIX = "auth.phone";
|
||||
private final String SMS_CONFIG_PREFIX = "sys.config";
|
||||
|
||||
@Resource
|
||||
CheckRouteCaptcha checkRouteCaptcha;
|
||||
|
||||
/**
|
||||
* @description: 发送短信验证码
|
||||
* @param: [phone]
|
||||
@@ -32,26 +39,38 @@ public class SchisandraSmsController {
|
||||
* @author zlg
|
||||
* @date: 2024/5/8 22:53
|
||||
*/
|
||||
@PostMapping("/sendByTemplate/{phone}")
|
||||
public Result sendByTemplate(@PathVariable("phone") String phone) {
|
||||
String prefix = redisUtil.buildKey(AUTH_PHONE_PREFIX, phone);
|
||||
String code = SmsUtils.getRandomInt(4);
|
||||
if (!redisUtil.exist(prefix)) {
|
||||
String key = redisUtil.buildKey(SMS_CONFIG_PREFIX, SmsConfigContext.SMS_CONFIG_KEY);
|
||||
String configId = redisUtil.get(key);
|
||||
if (configId == null) {
|
||||
log.error("短信配置不存在!");
|
||||
Result.fail("短信接口异常!");
|
||||
}
|
||||
SmsResponse smsResponse = SmsFactory.getSmsBlend(configId).sendMessage(phone, code);
|
||||
if (smsResponse.isSuccess()) {
|
||||
redisUtil.setNx(prefix, code, 60L * 5, SECONDS);
|
||||
return Result.ok("短信发送成功,5 分钟内有效,请注意查收!");
|
||||
@PostMapping("/sendByTemplate")
|
||||
public CaptchaResult sendByTemplate(@RequestBody SchisandraCaptchaDTO schisandraCaptchaDTO) {
|
||||
|
||||
if (schisandraCaptchaDTO.getToken() == null || schisandraCaptchaDTO.getDeg() == null || schisandraCaptchaDTO.getPhone() == null) {
|
||||
return CaptchaResult.fail("验证失败!");
|
||||
}
|
||||
String token = schisandraCaptchaDTO.getToken();
|
||||
String phone = schisandraCaptchaDTO.getPhone();
|
||||
Double deg = schisandraCaptchaDTO.getDeg();
|
||||
CaptchaResult captchaResult = checkRouteCaptcha.checkCaptcha(token, deg);
|
||||
if (captchaResult.getCode() == 0) {
|
||||
String prefix = redisUtil.buildKey(AUTH_PHONE_PREFIX, phone);
|
||||
String code = SmsUtils.getRandomInt(4);
|
||||
if (!redisUtil.exist(prefix)) {
|
||||
String key = redisUtil.buildKey(SMS_CONFIG_PREFIX, SmsConfigContext.SMS_CONFIG_KEY);
|
||||
String configId = redisUtil.get(key);
|
||||
if (configId == null) {
|
||||
log.error("短信配置不存在!");
|
||||
CaptchaResult.fail("短信接口异常!");
|
||||
}
|
||||
SmsResponse smsResponse = SmsFactory.getSmsBlend(configId).sendMessage(phone, code);
|
||||
if (smsResponse.isSuccess()) {
|
||||
redisUtil.setNx(prefix, code, 60L * 5, SECONDS);
|
||||
return CaptchaResult.ok("短信发送成功,5 分钟内有效,请注意查收!");
|
||||
} else {
|
||||
return CaptchaResult.fail("短信发送失败,请重试!");
|
||||
}
|
||||
} else {
|
||||
return Result.fail("短信发送失败,请重试!");
|
||||
return CaptchaResult.ok("短信已发送,请注意查看或稍后重试!");
|
||||
}
|
||||
} else {
|
||||
return Result.fail("短信已发送,请注意查看或稍后重试!");
|
||||
return CaptchaResult.fail("验证失败!");
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -118,5 +118,15 @@ public class SchisandraAuthUserDTO implements Serializable {
|
||||
*/
|
||||
private String confirmPassword;
|
||||
|
||||
/**
|
||||
* 旋转图片验证token
|
||||
*/
|
||||
private String token;
|
||||
|
||||
/**
|
||||
* 旋转图片验证的旋转角度
|
||||
*/
|
||||
private Double deg;
|
||||
|
||||
}
|
||||
|
||||
|
@@ -6,4 +6,5 @@ import lombok.Data;
|
||||
public class SchisandraCaptchaDTO {
|
||||
private String token;
|
||||
private Double deg;
|
||||
private String phone;
|
||||
}
|
||||
|
@@ -0,0 +1,42 @@
|
||||
package com.schisandra.auth.application.utils;
|
||||
|
||||
import com.schisandra.auth.common.entity.CaptchaResult;
|
||||
import com.schisandra.auth.common.redis.RedisUtil;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* @Classname CheckRouteCaptcha
|
||||
* @BelongsProject: schisandra-cloud-storage
|
||||
* @BelongsPackage: com.schisandra.auth.application.utils
|
||||
* @Author: landaiqing
|
||||
* @CreateTime: 2024-06-04 21:59
|
||||
* @Description: TODO
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Component
|
||||
public class CheckRouteCaptcha {
|
||||
@Resource
|
||||
private RedisUtil redisUtil;
|
||||
public final String authRotateCaptchaPrefix = "auth.rotate.captcha";
|
||||
|
||||
public CaptchaResult checkCaptcha(String token, Double deg) {
|
||||
if (deg == null && token == null) {
|
||||
return CaptchaResult.fail();
|
||||
}
|
||||
String prefix = redisUtil.buildKey(authRotateCaptchaPrefix, token);
|
||||
if (redisUtil.exist(prefix)) {
|
||||
double realNum = Double.parseDouble(redisUtil.get(prefix));
|
||||
if (Math.abs(realNum - deg) / realNum < 0.05) {
|
||||
redisUtil.del(prefix);
|
||||
return CaptchaResult.ok();
|
||||
} else {
|
||||
return CaptchaResult.fail();
|
||||
}
|
||||
} else {
|
||||
return CaptchaResult.fail();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -9,19 +9,22 @@ public class CaptchaResult<T> {
|
||||
|
||||
private String msg;
|
||||
|
||||
private Boolean success;
|
||||
|
||||
private T data;
|
||||
|
||||
public static CaptchaResult ok() {
|
||||
CaptchaResult result = new CaptchaResult();
|
||||
|
||||
result.setCode(0);
|
||||
result.setSuccess(true);
|
||||
result.setMsg("Success");
|
||||
return result;
|
||||
}
|
||||
|
||||
public static <T> CaptchaResult ok(T data) {
|
||||
CaptchaResult result = new CaptchaResult();
|
||||
|
||||
result.setSuccess(true);
|
||||
result.setCode(0);
|
||||
result.setMsg("Success");
|
||||
result.setData(data);
|
||||
@@ -30,14 +33,41 @@ public class CaptchaResult<T> {
|
||||
|
||||
public static CaptchaResult fail() {
|
||||
CaptchaResult result = new CaptchaResult();
|
||||
|
||||
result.setSuccess(false);
|
||||
result.setCode(1);
|
||||
result.setMsg("验证失败");
|
||||
return result;
|
||||
}
|
||||
|
||||
public static CaptchaResult failWithSuccess() {
|
||||
CaptchaResult result = new CaptchaResult();
|
||||
result.setSuccess(true);
|
||||
result.setCode(1);
|
||||
result.setMsg("验证失败");
|
||||
return result;
|
||||
}
|
||||
|
||||
// 登录验证特殊情况
|
||||
public static CaptchaResult failWithCode() {
|
||||
CaptchaResult result = new CaptchaResult();
|
||||
result.setSuccess(false);
|
||||
result.setCode(0);
|
||||
result.setMsg("验证成功");
|
||||
return result;
|
||||
}
|
||||
|
||||
public static <T> CaptchaResult failWithCode(T data) {
|
||||
CaptchaResult result = new CaptchaResult();
|
||||
result.setSuccess(false);
|
||||
result.setCode(0);
|
||||
result.setData(data);
|
||||
result.setMsg("验证成功");
|
||||
return result;
|
||||
}
|
||||
|
||||
public static <T> CaptchaResult fail(T data) {
|
||||
CaptchaResult result = new CaptchaResult();
|
||||
result.setSuccess(false);
|
||||
result.setCode(1);
|
||||
result.setMsg("验证失败");
|
||||
result.setData(data);
|
||||
|
Reference in New Issue
Block a user