需求:

注册-登录-修改密码⼀般需要发送验证码,但是容易被 攻击恶意调⽤。
⼿机短信轰炸机是批、循环给⼿机⽆限发送各种⽹ 站的注册验 证码短信的⽅法。

避免⾃⼰的⽹站被刷

  • 增加图形验证码(开发⼈员)
  • 单IP请求次数限制(开发⼈员)
  • 限制号码发送(⼀般短信提供商会做)

Kaptcha:⾕歌开源的⼀个可⾼度配置的实⽤验证码⽣成⼯具

  1. @Configuration
  2. public class CaptchaConf {
  3. /**
  4. * 验证码配置类
  5. * @return
  6. */
  7. @Bean
  8. @Qualifier("captchaProducer")
  9. public DefaultKaptcha captcha() {
  10. DefaultKaptcha kaptcha = new DefaultKaptcha();
  11. Properties properties = new Properties();
  12. //验证码个数
  13. properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "5");
  14. //验证码间隔
  15. properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "10");
  16. //干扰实现类
  17. properties.setProperty(Constants.KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise");
  18. //图片样式
  19. properties.setProperty(Constants.KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.WaterRipple");
  20. //文字来源
  21. properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_STRING, "0123456789abcd");
  22. Config config = new Config(properties);
  23. kaptcha.setConfig(config);
  24. return kaptcha;
  25. }
  26. }
  1. @RestController
  2. @RequestMapping("/captcha")
  3. public class TestCaptcha {
  4. @Resource
  5. private StringRedisTemplate stringRedisTemplate;
  6. @Autowired
  7. //@Qualifier("captchaProducer")
  8. private Producer captchaProducer;
  9. @GetMapping
  10. public void getCaptcha(HttpServletRequest request, HttpServletResponse response) {
  11. String key = getKey(request);
  12. String captchaCode = captchaProducer.createText();
  13. stringRedisTemplate.opsForValue().set(key,captchaCode,10, TimeUnit.MINUTES);
  14. BufferedImage image = captchaProducer.createImage(captchaCode);
  15. ServletOutputStream outputStream = null;
  16. try {
  17. outputStream = response.getOutputStream();
  18. ImageIO.write(image, "jpg", outputStream);
  19. outputStream.flush();
  20. outputStream.close();
  21. } catch (IOException e) {
  22. e.printStackTrace();
  23. }
  24. }
  25. public String getKey(HttpServletRequest request) {
  26. String ipAddr = CommonUtil.getIpAddr(request);
  27. String header = request.getHeader("User-Agent");
  28. String key = "user:captcha:" + CommonUtil.MD5(ipAddr+header);
  29. return key;
  30. }
  31. }
  1. public class CommonUtil {
  2. /**
  3. * 获取ip
  4. * @param request
  5. * @return
  6. */
  7. public static String getIpAddr(HttpServletRequest request) {
  8. String ipAddress = null;
  9. try {
  10. ipAddress = request.getHeader("x-forwarded-for");
  11. if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
  12. ipAddress = request.getHeader("Proxy-Client-IP");
  13. }
  14. if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
  15. ipAddress = request.getHeader("WL-Proxy-Client-IP");
  16. }
  17. if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
  18. ipAddress = request.getRemoteAddr();
  19. if (ipAddress.equals("127.0.0.1")) {
  20. // 根据网卡取本机配置的IP
  21. InetAddress inet = null;
  22. try {
  23. inet = InetAddress.getLocalHost();
  24. } catch (UnknownHostException e) {
  25. e.printStackTrace();
  26. }
  27. ipAddress = inet.getHostAddress();
  28. }
  29. }
  30. // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
  31. if (ipAddress != null && ipAddress.length() > 15) {
  32. if (ipAddress.indexOf(",") > 0) {
  33. ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
  34. }
  35. }
  36. } catch (Exception e) {
  37. ipAddress="";
  38. }
  39. return ipAddress;
  40. }
  41. public static String MD5(String data) {
  42. try {
  43. MessageDigest md = MessageDigest.getInstance("MD5");
  44. byte[] array = md.digest(data.getBytes("UTF-8"));
  45. StringBuilder sb = new StringBuilder();
  46. for (byte item : array) {
  47. sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
  48. }
  49. return sb.toString().toUpperCase();
  50. } catch (Exception exception) {
  51. }
  52. return null;
  53. }
  54. }