从构建分布式秒杀系统聊聊验证码 推荐 原创 小柒2015 2018-09-28 09:42:26 ©著作权 文章标签 秒杀 验证码 文章分类 网络安全 ©著作权归作者所有:来自51CTO博客作者小柒2015的原创作品,请联系作者获取转载授权,否则将追究法律责任 前言 为了拦截大部分请求,秒杀案例前端引入了验证码。淘宝上很多人吐槽,等输入完秒杀活动结束了,对,结束了...... 当然了,验证码的真正作用是,有效拦截刷单操作,让羊毛党空手而归。 验证码 那么到底什么是验证码呢?验证码作为一种人机识别手段,其终极目的,就是区分正常人和机器的操作。我们常见的互联网注册、登录、发帖、领优惠券、投票等等应用场景,都有被机器刷造成各类损失的风险。 目前常见的验证码形式多为图片验证码,即数字、字母、文字、图片物体等形式的传统字符验证码。这类验证码看似简单易操作,但实际用户体验较差(参见12306网站),且随着OCR技术和打码平台的利用,图片比较容易被破解,被破解之后就形同虚设。 这里我们使用腾讯的智能人机安全验证码,告别传统验证码的单点防御,十道安全栅栏打造立体全面的安全验证,将黑产拒之门外。 场景 下面我们来瞅瞅验证码轻松解决了那些场景安全问题: 登录注册,为你防护撞库×××、阻止注册机批量注册 活动秒杀,有效拦截刷单操作,让羊毛党空手而归 点赞发帖,有效解决广告屠版、恶意灌水、刷票问题 数据保护,防止自动机、爬虫盗取网页内容和数据 申请 申请地址:https://007.qq.com/product.html 在线体验:https://007.qq.com/online.html 只要一个QQ就可以免费申请,对于一般的企业OA系统或者个人博客网站,验证码免费套餐足够了已经,具备以下特点: 2000次/小时安全防护 支持免验证+分级验证 三分钟快速接入 全功能配置后台 支持HTTPS 阈值内流量无广告 2000次/小时的安全防护,一般很少达到如此效果,当然了即时超出阈值,顶多也就是多个广告而已。 接入 快读接入:https://007.qq.com/quick-start.html 接入与帮助提供了多种客户端和服务端的接入案例,这里我们使用我们秒杀案例中最熟悉的Java语言来接入。 前端 引入JS: <script src="https://ssl.captcha.qq.com/TCaptcha.js"></script> 页面元素: <!--点击此元素会自动激活验证码,不一定是button,其他标签也可以--> <!--id : 元素的id(必须)--> <!--data-appid : AppID(必须)--> <!--data-cbfn : 回调函数名(必须)--> <!--data-biz-state : 业务自定义透传参数(可选)--> <button id="TencentCaptcha" data-appid="*********" data-cbfn="callback">验证</button> JS回调: <script type="text/Javascript"> window.callback = function(res){ console.log(res) // res(未通过验证)= {ret: 1, ticket: null} // res(验证成功) = {ret: 0, ticket: "String", randstr: "String"} if(res.ret === 0){ startSeckill(res) } } //后台验证ticket,并进入秒杀队列 function startSeckill(res){ $.ajax({ url : "startSeckill", type : 'post', data : {'ticket' : res.ticket,'randstr':res.randstr}, success : function(result) { //验证是否通过,提示用户 } }); } </script> 后端 @Api(tags = "秒杀商品") @RestController @RequestMapping("/seckillPage") public class SeckillPageController { @Autowired private ActiveMQSender activeMQSender; //自定义工具类 @Autowired private HttpClient httpClient; //这里自行配置参数 @Value("${qq.captcha.url}") private String url; @Value("${qq.captcha.aid}") private String aid; @Value("${qq.captcha.AppSecretKey}") private String appSecretKey; @RequestMapping("/startSeckill") public Result startSeckill(String ticket,String randstr,HttpServletRequest request) { HttpMethod method =HttpMethod.POST; MultiValueMap<String, String> params= new LinkedMultiValueMap<String, String>(); params.add("aid", aid); params.add("AppSecretKey", appSecretKey); params.add("Ticket", ticket); params.add("Randstr", randstr); params.add("UserIP", IPUtils.getIpAddr(request)); String msg = httpClient.client(url,method,params); /** * response: 1:验证成功,0:验证失败,100:AppSecretKey参数校验错误[required] * evil_level:[0,100],恶意等级[optional] * err_msg:验证错误信息[optional] */ //{"response":"1","evil_level":"0","err_msg":"OK"} JSONObject json = JSONObject.parseObject(msg); String respOnse= (String) json.get("response"); if("1".equals(response)){ //进入队列、假数据而已 Destination destination = new ActiveMQQueue("seckill.queue"); activeMQSender.sendChannelMess(destination,1000+";"+1); return Result.ok(); }else{ return Result.error("验证失败"); } } } 自定义请求工具类 HttpClient: @Service public class HttpClient { public String client(String url, HttpMethod method, MultiValueMap<String, String> params){ RestTemplate client = new RestTemplate(); HttpHeaders headers = new HttpHeaders(); // 请勿轻易改变此提交方式,大部分的情况下,提交方式都是表单提交 headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<MultiValueMap<String, String>>(params, headers); // 执行HTTP请求 ResponseEntity<String> respOnse= client.exchange(url, HttpMethod.POST, requestEntity, String.class); return response.getBody(); } } 获取IP地址工具类 IPUtils : /** * IP地址 */ public class IPUtils { private static Logger logger = LoggerFactory.getLogger(IPUtils.class); /** * 获取IP地址 * 使用Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址 * 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址 */ public static String getIpAddr(HttpServletRequest request) { String ip = null; try { ip = request.getHeader("x-forwarded-for"); if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (StringUtils.isEmpty(ip) || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_CLIENT_IP"); } if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_X_FORWARDED_FOR"); } if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } } catch (Exception e) { logger.error("IPUtils ERROR ", e); } // 使用代理,则获取第一个IP地址 if (StringUtils.isEmpty(ip) && ip.length() > 15) { if (ip.indexOf(",") > 0) { ip = ip.substring(0, ip.indexOf(",")); } } return ip; } } 案例效果图 启动项目访问:http://localhost:8080/seckill/1000.shtml 定制接入 在系统登录的时候,我们需要先校验用户名以及密码,然后调用验证码操作,这里就需要我们定制接入了。 <!-- 项目中使用了Vue --> <div class="log_btn" @click="login" >登录</div> login: function () { //这里校验用户名以及密码 // 直接生成一个验证码对象 var captcha = new TencentCaptcha('2001344788', function(res) { if(res.ret === 0){//回调成功 var data = {'username':username,'password':password,'ticket':res.ticket,'randstr':res.randstr} $.ajax({ type: "POST", url: "sys/loginCaptcha", data: data, dataType: "json", success: function(result){ //校验是否成功 } }); } }); captcha.show(); // 显示验证码 }, 后台监控 腾讯后台还提供了简单实用的数据监控,如下: 小结 总体来说,系统接入人机验证码还是很方便的,并没有技术难点,难点已经被提供商封装,我们只需要简单的调用即可。 秒杀案例:https://gitee.com/52itstyle/spring-boot-seckill 演示案例(点击生成按钮):http://jichou.52itstyle.com 赞 收藏 评论 分享 举报 上一篇:从构建分布式秒杀系统聊聊分布式锁 下一篇:SpringBoot开发案例之整合Dubbo分布式服务 提问和评论都可以,用心的回复会被更多人看到 评论 发布评论 全部评论 () 最热 最新 相关文章 生成验证码-超简单 轻松应对验证挑战:简单验证码的实现方法! 验证码 Java 华为云分布式云原生UCS,助力MetaERP构建企业级高可用分布式业务 本文我们将结合华为 MetaERP 的生产应用案例详细介绍 UCS 多集群的容灾多活实践。 UCS MetaERP 分布式 容器 EasyCaptcha-开源图形验证码新标杆! EasyCaptcha:让您的网站告别垃圾注册! 验证码 java 从构建分布式秒杀系统聊聊验证码 前言为了拦截大部分请求,秒杀案例前端引入了验证码。淘宝上很多人吐槽,等输入完秒杀活动结束了,对,结束了...... 当然了,验证码的真正作用是,有效拦截刷单操作,让羊毛党空手而归。验证码那么到底什么是验证码呢?验证码作为一种人机识别手段,其终极目的,就是区分正常人和机器的操作。我们常见的互联网注册、登录、发帖、领优惠券、投票等等应用场景,都有被机器刷造成各类损失的风险。目前常见的验证码形式多为图片 分布式 秒杀系统 从构建分布式秒杀系统聊聊分布式锁 前言最近懒成一坨屎,学不动系列一波接一波,大多还都是底层原理相关的。上周末抽时间重读了周志明大湿的 JVM 高效并发部分,每读一遍都有不同的感悟。路漫漫,借此,把前段时间搞着玩的秒杀案例中的分布式锁深入了解一下。案例介绍在尝试了解分布式锁之前,大家可以想象一下,什么场景下会使用分布式锁?单机应用架构中,秒杀案例使用ReentrantLcok或者synchronized来达到秒杀商品互斥的目的。然而 分布式 从构建分布式秒杀系统聊聊线程池 前言从0到1构建分布式秒杀系统案例的代码已经全部上传至码云,文章也被分发到各个平台。其中也收到了不少小伙伴喜欢和反馈,有网友如是说:说实话,能用上的不多,中小企业都不可能用到,大型企业也不是一个人就能搞起的,大部分人一辈子都用不上,等有这个需要再搞吧。我的观点是赞同但不支持,基本上任何事物都是呈金字塔分布,互联网也不例外,也就是说大部分可能都是普通人,接触不到所谓大厂的应用场景。但是,书到用时方恨 线程池 分布式 从构建分布式秒杀系统聊聊限流特技 俗话说的好,冰冻三尺非一日之寒,滴水穿石非一日之功,罗马也不是一天就建成的。两周前秒杀案例初步成型,分享到了中国最大的同×××友网站-码云。同时也收到了不少小伙伴的建议和投诉。我从不认为分布式、集群、秒杀这些就应该是大厂的专利,在互联网的今天无论什么时候都要时刻武装自己,只有这样,也许你的春天就在明天。在开发秒杀系统案例的过程中,前面主要分享了队列、缓存、锁和分 秒杀 限流 分布式 OpenResty 从构建分布式秒杀系统聊聊WebSocket推送通知 前言秒杀架构到后期,我们采用了消息队列的形式实现抢购逻辑,那么之前抛出过这样一个问题:消息队列异步处理完每个用户请求后,如何通知给相应用户秒杀成功?场景映射首先,我们举一个生活中比较常见的例子:我们去银行办理业务,一般会选择相关业务打印一个排号纸,然后就可以坐在小板凳上玩着手机,等待被小喇叭报号。当小喇叭喊到你所持有的号码,就可以拿着排号纸去柜台办理自己的业务。这里,假设当我们取排号纸的时候,银行 秒杀 websocket 异步 轮询 消息队列 从构建分布式秒杀系统聊聊Disruptor高性能队列 前言秒杀架构持续优化中,基于自身认知不足之处在所难免,也请大家指正,共同进步。文章标题来自码友<tukangzheng>的建议,希望可以把阻塞队列ArrayBlockingQueue这个队列替换成Disruptor,由于之前曾接触过这个东西,听说很不错,正好借此机会整合进来。简介LMAXDisruptor是一个高性能的线程间消息库。它源于LMAX对并发性,性能和非阻塞算法的研究,如今构 Disruptor 秒杀 从构建分布式秒杀系统聊聊为什么不用synchronized 前言技术没有高低之分,适合自己的就是最好的。只有努力扩展自己的知识边界,才能探索更多未知领域。案例在分析为什么不用synchronized这个问题之前,我们先用代码说话,LockDemo测试案例:/***案例测试*@author*/publicclassLockDemo{privatestaticLocklock=newReentrantLock();privatestaticintnum1=0; Java 架构 程序员 分布式 synchronized 从构建分布式秒杀系统聊聊Lock锁使用中的坑 前言在单体架构的秒杀活动中,为了减轻DB层的压力,这里我们采用了Lock锁来实现秒杀用户排队抢购。然而很不幸的是尽管使用了锁,但是测试过程中仍然会超卖,执行了N多次发现依然有问题。输出一下代码吧,可能大家看的比较真切:@Service("seckillService")public class SeckillServiceImpl implements ISeckillService { / 分布式秒杀系统 分布式验证码登录方案 本文大纲前言前后端未分离的验证码登录方案验证码生成流程如下登录验证流程如下前后端分离的验证码登录方案验证码生成流程如下登录验证流程如下动手撸轮子Kaptcha介绍新建项目并加入依赖验证码获取和查看代码获取 前言为了防止世界被破坏,为了守护世界的和平。。。说错了,重来~为了防止验证系统被暴力破解,很多系统都增加了验证码效 java 实战:SpringBoot分布式验证码登录方案 本文大纲前言前后端未分离的验证码登录方案验证码生成流程如下登录验证流程如下前后端分离的验证码登录方案验证码生 redis 验证码 spring maven xml SpringBoot开发案例从0到1构建分布式秒杀系统 前言最近,被推送了不少秒杀架构的文章,忙里偷闲自己也总结了一下互联网平台秒杀架构设计,当然也借鉴了不少同学的思路。俗话说,脱离案例讲架构都是耍流氓,最终使用SpringBoot模拟实现了部分秒杀场景,同时跟大家分享交流一下。秒杀场景秒杀场景无非就是多个用户在同时抢购一件或者多件商品,专用词汇就是所谓的高并发。现实中经常被大家喜闻乐见的场景,一群大妈抢购打折鸡蛋的画面一定不会陌生,如此场面让服务员大 SpringBoot redis kafka 秒杀 聊聊分布式 欢迎关注公众号:java4all↓↓↓分布式系列目录,点击直接进入文章↓↓↓,也可 分布式 分布式锁 分布式事务 Cloud 分布式系统?分布式事务?秒杀设计思路! 什么是分布式?分布式更多的一个概念,是为了解决单个物理服务器容量和性能 memcached 运维 数据库 协调者 redis 分布式秒杀系统的设计 不知道你在面试的过程中有没有被问到如何设计一个分布式秒杀系统?本篇博客根据大神们的梳理的体系并结合自己实际的项 分布式 秒杀系统 抢购 溪源 系统设计 聊聊分布式锁 1.背景对于锁大家肯定不会陌生,在Java中synchronized关键字和ReentrantLock可重入锁在我们的代码中是经常见的,一般我们用其在多线程环境中控制对资源的并发访问,但是随着分布式的快速发展,本地的加锁往往不能满足我们的需要,在我们的分布式环境中上面加锁的方法就会失去作用。于是人们为了在分布式环境中也能实现本地锁的效果,也是纷纷各出其招,今天让我们来聊一聊一般分布式锁实现的套路。 java