需求:
注册-登录-修改密码⼀般需要发送验证码,但是容易被 攻击恶意调⽤。
⼿机短信轰炸机是批、循环给⼿机⽆限发送各种⽹ 站的注册验 证码短信的⽅法。
避免⾃⼰的⽹站被刷
- 增加图形验证码(开发⼈员)
- 单IP请求次数限制(开发⼈员)
- 限制号码发送(⼀般短信提供商会做)
Kaptcha:⾕歌开源的⼀个可⾼度配置的实⽤验证码⽣成⼯具
@Configurationpublic class CaptchaConf {/*** 验证码配置类* @return*/@Bean@Qualifier("captchaProducer")public DefaultKaptcha captcha() {DefaultKaptcha kaptcha = new DefaultKaptcha();Properties properties = new Properties();//验证码个数properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "5");//验证码间隔properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "10");//干扰实现类properties.setProperty(Constants.KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise");//图片样式properties.setProperty(Constants.KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.WaterRipple");//文字来源properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_STRING, "0123456789abcd");Config config = new Config(properties);kaptcha.setConfig(config);return kaptcha;}}
@RestController@RequestMapping("/captcha")public class TestCaptcha {@Resourceprivate StringRedisTemplate stringRedisTemplate;@Autowired//@Qualifier("captchaProducer")private Producer captchaProducer;@GetMappingpublic void getCaptcha(HttpServletRequest request, HttpServletResponse response) {String key = getKey(request);String captchaCode = captchaProducer.createText();stringRedisTemplate.opsForValue().set(key,captchaCode,10, TimeUnit.MINUTES);BufferedImage image = captchaProducer.createImage(captchaCode);ServletOutputStream outputStream = null;try {outputStream = response.getOutputStream();ImageIO.write(image, "jpg", outputStream);outputStream.flush();outputStream.close();} catch (IOException e) {e.printStackTrace();}}public String getKey(HttpServletRequest request) {String ipAddr = CommonUtil.getIpAddr(request);String header = request.getHeader("User-Agent");String key = "user:captcha:" + CommonUtil.MD5(ipAddr+header);return key;}}
public class CommonUtil {/*** 获取ip* @param request* @return*/public static String getIpAddr(HttpServletRequest request) {String ipAddress = null;try {ipAddress = request.getHeader("x-forwarded-for");if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getHeader("Proxy-Client-IP");}if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getHeader("WL-Proxy-Client-IP");}if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getRemoteAddr();if (ipAddress.equals("127.0.0.1")) {// 根据网卡取本机配置的IPInetAddress inet = null;try {inet = InetAddress.getLocalHost();} catch (UnknownHostException e) {e.printStackTrace();}ipAddress = inet.getHostAddress();}}// 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割if (ipAddress != null && ipAddress.length() > 15) {if (ipAddress.indexOf(",") > 0) {ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));}}} catch (Exception e) {ipAddress="";}return ipAddress;}public static String MD5(String data) {try {MessageDigest md = MessageDigest.getInstance("MD5");byte[] array = md.digest(data.getBytes("UTF-8"));StringBuilder sb = new StringBuilder();for (byte item : array) {sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));}return sb.toString().toUpperCase();} catch (Exception exception) {}return null;}}
