Преглед изворни кода

济南手机短信添加验证码

yuhongqi пре 3 недеља
родитељ
комит
c0f81e1c98

+ 10 - 0
fs-common/src/main/java/com/fs/common/constant/Constants.java

@@ -64,6 +64,11 @@ public class Constants
      */
     public static final String CAPTCHA_CODE_KEY = "captcha_codes:";
 
+    /**
+     * App登录图形验证码 redis key
+     */
+    public static final String APP_LOGIN_CAPTCHA_CODE_KEY = "app_login:captcha:";
+
     /**
      * 登录用户 redis key
      */
@@ -84,6 +89,11 @@ public class Constants
      */
     public static final Integer CAPTCHA_EXPIRATION = 2;
 
+    /**
+     * App登录图形验证码有效期(分钟)
+     */
+    public static final Integer APP_LOGIN_CAPTCHA_EXPIRATION = 3;
+
     /**
      * 令牌
      */

+ 146 - 0
fs-user-app/src/main/java/com/fs/app/controller/AppLoginController.java

@@ -10,6 +10,8 @@ import com.fs.app.utils.WxUtil;
 import com.fs.common.VerifyCodeUtil;
 import com.fs.common.annotation.Log;
 import com.fs.common.annotation.RepeatSubmit;
+import com.fs.common.constant.Constants;
+import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.entity.SysDictData;
 import com.fs.common.core.page.TableDataInfo;
@@ -20,7 +22,9 @@ import com.fs.common.service.ISmsService;
 import com.fs.common.utils.CloudHostUtils;
 import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.ip.IpUtils;
+import com.fs.common.utils.sign.Base64;
 import com.fs.common.utils.sign.Md5Utils;
+import com.fs.common.utils.uuid.IdUtils;
 import com.fs.core.config.WxOpenProperties;
 import com.fs.course.domain.FsCoursePlaySourceConfig;
 import com.fs.course.domain.LuckyBag;
@@ -34,12 +38,14 @@ import com.fs.his.mapper.FsUserWxMapper;
 import com.fs.his.service.IFsUserCouponService;
 import com.fs.his.service.IFsUserNewTaskService;
 import com.fs.his.service.IFsUserService;
+import com.fs.his.utils.PhoneUtil;
 import com.fs.his.vo.FsUserRegisterParam;
 import com.fs.im.dto.OpenImResponseDTO;
 import com.fs.im.service.OpenIMService;
 import com.fs.qw.service.ILuckyBagService;
 import com.fs.system.service.ISysDictTypeService;
 import com.fs.utils.ContentCheckUtil;
+import com.google.code.kaptcha.Producer;
 import io.netty.util.internal.StringUtil;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -49,10 +55,16 @@ import org.apache.ibatis.annotations.Param;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.FastByteArrayOutputStream;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
+import javax.annotation.Resource;
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
 import java.util.*;
 import java.util.concurrent.TimeUnit;
 
@@ -103,6 +115,16 @@ public class AppLoginController extends AppBaseController{
 
     @Autowired
     private ISysDictTypeService dictTypeService;
+
+    @Resource(name = "captchaProducer")
+    private Producer captchaProducer;
+
+    @Resource(name = "captchaProducerMath")
+    private Producer captchaProducerMath;
+
+    @Value("${fs.captchaType}")
+    private String captchaType;
+
     @ApiOperation("注册app用户")
     @PostMapping("/register")
     @RepeatSubmit
@@ -1077,6 +1099,130 @@ public class AppLoginController extends AppBaseController{
         return R.ok("验证码已发送");
     }
 
+    @ApiOperation("获取App登录图形验证码")
+    @GetMapping("/appLoginCaptchaImage")
+    public AjaxResult getAppLoginCaptchaImage() throws IOException {
+        String uuid = IdUtils.simpleUUID();
+        String verifyKey = Constants.APP_LOGIN_CAPTCHA_CODE_KEY + uuid;
+
+        String capStr;
+        String code;
+        BufferedImage image;
+
+        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 = code = captchaProducer.createText();
+            image = captchaProducer.createImage(capStr);
+        }
+
+        redisCache.setCacheObject(verifyKey, code, Constants.APP_LOGIN_CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
+
+        FastByteArrayOutputStream os = new FastByteArrayOutputStream();
+        ImageIO.write(image, "jpg", os);
+
+        AjaxResult ajax = AjaxResult.success();
+        ajax.put("uuid", uuid);
+        ajax.put("img", Base64.encode(os.toByteArray()));
+        return ajax;
+    }
+
+    @ApiOperation("发送短信验证码(需图形验证码)")
+    @PostMapping("/sendCodeWithCaptcha")
+    public R sendCodeWithCaptcha(@RequestBody Map<String, String> body) {
+        String phone = body.get("phone");
+        String captchaCode = body.get("captchaCode");
+        String captchaUuid = body.get("captchaUuid");
+
+        if (!PhoneUtil.isNormalPhone(phone)) {
+            return R.error("手机号格式不正确");
+        }
+
+        R captchaError = validateAppLoginCaptcha(captchaCode, captchaUuid);
+        if (captchaError != null) {
+            return captchaError;
+        }
+
+        String smsCodeKey = "sms:code:" + phone;
+        String smsCooldownKey = "sms:cooldown:" + phone;
+
+        if (redisCache.getCacheObject(smsCooldownKey) != null) {
+            return R.error("验证码已发送,请稍后再试");
+        }
+
+        String smsCode = VerifyCodeUtil.generateCode();
+        smsService.sendCaptcha(phone, smsCode, "验证码");
+        redisCache.setCacheObject(smsCodeKey, smsCode, 180, TimeUnit.SECONDS);
+        redisCache.setCacheObject(smsCooldownKey, "1", 60, TimeUnit.SECONDS);
+
+        return R.ok("验证码已发送");
+    }
+
+    @ApiOperation("手机号登录(需图形验证码)")
+    @PostMapping("/loginByPhoneWithCaptcha")
+    public R loginByPhoneWithCaptcha(@RequestBody Map<String, String> map) {
+        String phone = map.get("phone");
+        String code = map.get("code");
+        String captchaCode = map.get("captchaCode");
+        String captchaUuid = map.get("captchaUuid");
+
+        if (!PhoneUtil.isNormalPhone(phone)) {
+            return R.error("手机号格式不正确");
+        }
+
+        R captchaError = validateAppLoginCaptcha(captchaCode, captchaUuid);
+        if (captchaError != null) {
+            return captchaError;
+        }
+
+        String encryptPhone = encryptPhone(phone);
+        List<FsUser> user = userService.selectFsUserListByPhone(encryptPhone);
+        if (CollectionUtil.isEmpty(user)) {
+            user = userService.selectFsUserListByPhone(encryptPhoneOldKey(phone));
+        }
+        if (CollectionUtil.isEmpty(user)) {
+            user = userService.selectFsUserListByPhone(phone);
+        }
+        if (CollectionUtil.isEmpty(user)) {
+            return R.error("此电话号码未绑定用户");
+        }
+        if (user.size() > 1) {
+            user.removeIf(fsUser -> StringUtils.isEmpty(fsUser.getHistoryApp()));
+        }
+
+        String redisCode = redisCache.getCacheObject("sms:code:" + phone);
+        if (StringUtils.isEmpty(redisCode)) {
+            return R.error("验证码已过期,请重新发送");
+        }
+        if (!redisCode.equals(code)) {
+            return R.error("验证码错误");
+        }
+
+        redisCache.deleteObject(Constants.APP_LOGIN_CAPTCHA_CODE_KEY + captchaUuid);
+        updateExistingUserJpushId(user.get(0), map.get("jpushId"));
+        updateLoginDevice(user.get(0).getUserId(), map.get("loginDevice"), map.get("source"));
+
+        return generateTokenAndReturn(user.get(0));
+    }
+
+    private R validateAppLoginCaptcha(String captchaCode, String captchaUuid) {
+        if (StringUtils.isEmpty(captchaUuid) || StringUtils.isEmpty(captchaCode)) {
+            return R.error("请输入图形验证码");
+        }
+        String verifyKey = Constants.APP_LOGIN_CAPTCHA_CODE_KEY + captchaUuid;
+        String captcha = redisCache.getCacheObject(verifyKey);
+        if (captcha == null) {
+            return R.error("图形验证码已过期,请重新获取");
+        }
+        if (!captchaCode.equalsIgnoreCase(captcha)) {
+            return R.error("图形验证码错误");
+        }
+        return null;
+    }
+
     private List<FsUser> findUsersByPhone(String phone) {
         // 先根据加密手机号查询用户
         String jiami = (encryptPhone(phone));