wjli
2024-04-10 81af4cff627b7ec1e125b90f4fd57392c6d70588
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package cn.exrick.xboot.base.controller.common;
 
import cn.exrick.xboot.core.common.annotation.RateLimiter;
import cn.exrick.xboot.core.common.constant.CommonConstant;
import cn.exrick.xboot.core.common.redis.RedisTemplateHelper;
import cn.exrick.xboot.core.common.sms.SmsUtil;
import cn.exrick.xboot.core.common.utils.CommonUtil;
import cn.exrick.xboot.core.common.utils.CreateVerifyCode;
import cn.exrick.xboot.core.common.utils.IpInfoUtil;
import cn.exrick.xboot.core.common.utils.ResultUtil;
import cn.exrick.xboot.core.common.vo.Result;
import cn.exrick.xboot.core.service.SettingService;
import cn.exrick.xboot.core.service.UserService;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
 
/**
 * @author Exrickx
 */
@Api(tags = "验证码接口")
@RequestMapping("/xboot/common/captcha")
@RestController
@Transactional
@Slf4j
public class CaptchaController {
 
    @Autowired
    private SmsUtil smsUtil;
 
    @Autowired
    private RedisTemplateHelper redisTemplate;
 
    @Autowired
    private IpInfoUtil ipInfoUtil;
 
    @Autowired
    private UserService userService;
 
    @Autowired
    private SettingService settingService;
 
    @RequestMapping(value = "/init", method = RequestMethod.GET)
    @ApiOperation(value = "初始化验证码")
    public Result<Object> initCaptcha() {
 
        String captchaId = IdUtil.simpleUUID();
        String code = new CreateVerifyCode().randomStr(4);
        // 缓存验证码
        redisTemplate.set(captchaId, code, 2L, TimeUnit.MINUTES);
        Map<String,String> map = new HashMap<String,String>();
        map.put("captchaId",captchaId);
        map.put("code",code);
        return ResultUtil.data(map);
    }
 
    @RequestMapping(value = "/draw/{captchaId}", method = RequestMethod.GET)
    @ApiOperation(value = "根据验证码ID获取图片")
    public void drawCaptcha(@PathVariable("captchaId") String captchaId,
                            HttpServletResponse response) throws IOException {
 
        // 得到验证码 生成指定验证码
        String code = redisTemplate.get(captchaId);
        CreateVerifyCode vCode = new CreateVerifyCode(116, 36, 4, 10, code);
        response.setContentType("image/png");
        vCode.write(response.getOutputStream());
    }
 
    @RequestMapping(value = "/sendRegistSms/{mobile}", method = RequestMethod.GET)
    @ApiOperation(value = "发送注册短信验证码")
    public Result<Object> sendRegistSmsCode(@PathVariable String mobile, HttpServletRequest request) {
 
        return sendSms(mobile, 2, 0, request);
    }
 
    @RequestMapping(value = "/sendLoginSms/{mobile}", method = RequestMethod.GET)
    @ApiOperation(value = "发送登录短信验证码")
    @RateLimiter(name="sendLoginSms", rate = 1, ipLimit = true)
    public Result<Object> sendLoginSmsCode(@PathVariable String mobile, HttpServletRequest request) {
 
        return sendSms(mobile, 1, 0, request);
    }
 
    @RequestMapping(value = "/sendResetSms/{mobile}", method = RequestMethod.GET)
    @ApiOperation(value = "发送重置密码短信验证码")
    public Result<Object> sendResetSmsCode(@PathVariable String mobile, HttpServletRequest request) {
 
        return sendSms(mobile, 1, 5, request);
    }
 
    @RequestMapping(value = "/sendEditMobileSms/{mobile}", method = RequestMethod.GET)
    @ApiOperation(value = "发送修改手机短信验证码")
    public Result<Object> sendEditMobileSmsCode(@PathVariable String mobile, HttpServletRequest request) {
 
        if (userService.findByMobile(mobile) != null) {
            return ResultUtil.error("该手机号已绑定账户");
        }
        return sendSms(mobile, 0, 0, request);
    }
 
    /**
     * @param mobile       手机号
     * @param range        发送范围 0发送给所有手机号 1只发送给注册手机 2只发送给未注册手机
     * @param templateType 0通用模版 1注册 2登录 3修改手机 4修改密码 5重置密码 6工作流模版
     */
    public Result<Object> sendSms(String mobile, Integer range, Integer templateType, HttpServletRequest request) {
 
        if (range == 1 && userService.findByMobile(mobile) == null) {
            return ResultUtil.error("手机号未注册");
        } else if (range == 2 && userService.findByMobile(mobile) != null) {
            return ResultUtil.error("手机号已注册");
        }
        // IP限流 1分钟限1个请求
        String key = "sendSms:" + ipInfoUtil.getIpAddr(request);
        String value = redisTemplate.get(key);
        if (StrUtil.isNotBlank(value)) {
            return ResultUtil.error("您发送的太频繁啦,请稍后再试");
        }
        // 生成6位数验证码
        String code = CommonUtil.getRandomNum();
        // 缓存验证码
        redisTemplate.set(CommonConstant.PRE_SMS + mobile, code, 5L, TimeUnit.MINUTES);
        // 发送验证码
        smsUtil.sendCode(mobile, code, templateType);
        // 请求成功 标记限流
        redisTemplate.set(key, "sended", 1L, TimeUnit.MINUTES);
        return ResultUtil.success("发送短信验证码成功");
    }
}