从构建分布式秒杀系统聊聊验证码 给大家推荐8个SpringBoot精选项目
前言
为了拦截大部分请求,秒杀案例前端引入了验证码。淘宝上很多人吐槽,等输入完秒杀活动结束了,对,结束了...... 当然了,验证码的真正作用是,有效拦截刷单操作,让羊毛党空手而归。
验证码
那么到底什么是验证码呢?验证码作为一种人机识别手段,其终极目的,就是区分正常人和机器的操作。我们常见的互联网注册、登录、发帖、领优惠券、投票等等应用场景,都有被机器刷造成各类损失的风险。
目前常见的验证码形式多为图片验证码,即数字、字母、文字、图片物体等形式的传统字符验证码。这类验证码看似简单易操作,但实际用户体验较差(参见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
项目案例
项目一:支付服务
简介:支付服务:支付宝、微信、银联详细 代码案例,目前已经1900+Star。十分钟让你快速搭建一个支付服务,内附各种教程。
项目地址:https://gitee.com/52itstyle/spring-boot-pay
项目二:秒杀案例
简介:从0到1构建分布式秒杀系统,脱离案例讲架构都是耍流氓,码云GVP项目。这个是自5月以来最上心的一个项目,尽管只是一个案例,但是从中也学到了不少知识。
项目地址:https://gitee.com/52itstyle/spring-boot-seckill
项目三:邮件服务
简介:邮件发送服务,文本,附件,模板,队列,多线程,定时任务实现多种功能。
项目地址:https://gitee.com/52itstyle/spring-boot-mail
项目四:全文搜索服务
简介:ES全文搜索引擎,基于Elasticsearch构建网站日志处理系统,通过数据同步工具等一些列开源组件来快速构建一个日志处理系统,项目雏形初步成型中。
项目地址:https://gitee.com/52itstyle/spring-boot-elasticsearch
项目五:任务管理系统
简介:基于spring-boot+quartz的CRUD任务管理系统 。
项目地址:https://gitee.com/52itstyle/spring-boot-quartz
项目六:在线文档管理系统
简介:spring-boot-doc是一款针对IT团队开发的简单好用的文档管理系统。
项目地址:https://gitee.com/52itstyle/spring-boot-doc
项目七:分布式文件系统
简介:没什么好介绍的,集成了Fastdfs而已。
项目地址:https://gitee.com/52itstyle/spring-boot-fastdfs
项目八:讯飞语音
简介:讯飞语音JavaWeb语音合成解决方案。
项目地址:https://gitee.com/52itstyle/xufei_msc
小结
总结这一年来,收获还是蛮大的,通过开源本身技能得到提升,同时也接触了不少热爱技术的小伙伴。
没有对比就没有伤害,你一直想成为优秀的人,可是你却没有付出一丁点而的努力。你想想比你优秀的人都还在努力,你有什么资格不去努力!山无棱天地合,喂点鸡汤给大家。
从构建分布式秒杀系统聊聊验证码 给大家推荐8个SpringBoot精选项目的更多相关文章
- 从构建分布式秒杀系统聊聊Disruptor高性能队列
前言 秒杀架构持续优化中,基于自身认知不足之处在所难免,也请大家指正,共同进步.文章标题来自码友 简介 LMAX Disruptor是一个高性能的线程间消息库.它源于LMAX对并发性,性能和非阻塞算法 ...
- 从构建分布式秒杀系统聊聊Lock锁使用中的坑
前言 在单体架构的秒杀活动中,为了减轻DB层的压力,这里我们采用了Lock锁来实现秒杀用户排队抢购.然而很不幸的是尽管使用了锁,但是测试过程中仍然会超卖,执行了N多次发现依然有问题.输出一下代码吧,可 ...
- 从构建分布式秒杀系统聊聊WebSocket推送通知
秒杀架构到后期,我们采用了消息队列的形式实现抢购逻辑,那么之前抛出过这样一个问题:消息队列异步处理完每个用户请求后,如何通知给相应用户秒杀成功? 场景映射 首先,我们举一个生活中比较常见的例子:我们去 ...
- SpringBoot开发案例从0到1构建分布式秒杀系统
前言 最近,被推送了不少秒杀架构的文章,忙里偷闲自己也总结了一下互联网平台秒杀架构设计,当然也借鉴了不少同学的思路.俗话说,脱离案例讲架构都是耍流氓,最终使用SpringBoot模拟实现了部分秒杀场 ...
- 使用.net core构建分布式SAAS系统(目录)
一 前言 二 项目背景 三 项目架构-从单体应用到微服务 四 大数据量下的分库分表 五 缓存处理--进程内缓存与Redis的使用 六 使用MNS队列来流量削峰 七 百万Job的任务调度系统 八 每天1 ...
- 利用开源架构ELK构建分布式日志系统
问题导读 1.ELK产生的背景?2.ELK的基本组成模块以及各个模块的作用?3.ELK的使用总计有哪些? 背景 日志,对每个系统来说,都是很重要,又很容易被忽视的部分.日志里记录了程序执行的关键信息, ...
- Java秒杀系统实战系列~构建SpringBoot多模块项目
摘要:本篇博文是“Java秒杀系统实战系列文章”的第二篇,主要分享介绍如何采用IDEA,基于SpringBoot+SpringMVC+Mybatis+分布式中间件构建一个多模块的项目,即“秒杀系统”! ...
- Redis分布式锁----悲观锁实现,以秒杀系统为例
摘要:本文要实现的是一种使用redis来实现分布式锁. 1.分布式锁 分布式锁在是一种用来安全访问分式式机器上变量的安全方案,一般用在全局id生成,秒杀系统,全局变量共享.分布式事务等.一般会有两种实 ...
- springboot项目:Redis分布式锁的使用(模拟秒杀系统)
模拟秒杀系统: 第一步:编写Service package com.payease.service; /** * liuxiaoming * 2017-12-14 */ public interfac ...
随机推荐
- java之判断输入的数是否为素数
import java.util.Scanner; public class TestIsSushu { public static void main(String[] args) { Scanne ...
- maven项目修改项目名
修改pom文件下面三处
- HDU 4642 Fliping game (2013多校4 1011 简单博弈)
Fliping game Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Tota ...
- django --01 helloworld样例入门
很好的一个django教程:https://www.w3cschool.cn/django/django-first-app.html django版本:1.8 1.创建django工程 django ...
- 使用Hexo快速搭建一个博客,并部署到github
本文旨在记录一下我在通过hexo搭建一个博客,并将其部署在github上面的过程,也供我自己在以后的使用过程中能够快速学习和参考.需要看更详细或者官方文档的可以点击Hexo官方文档进行查看. 安装前提 ...
- ylbtech-LanguageSamples-Indexers(索引器)
ylbtech-Microsoft-CSharpSamples:ylbtech-LanguageSamples-Indexers(索引器) 1.A,示例(Sample) 返回顶部 “索引器”示例 本示 ...
- iOS:iOS中的几种动画
本文来自收藏,感谢原创博主. iOS中的动画 摘要 本文主要介绍核iOS中的动画:核心动画Core Animation, UIView动画, Block动画, UIImageView的帧动画. 核心动 ...
- django queryset合并问题
今天在实现搜索时遇到一个问题,如何同时搜索model里面的title以及content和category字典 contents = Blog.objects.filter(content__conta ...
- cpu gpu数据同步
https://developer.apple.com/documentation/metal/advanced_command_setup/cpu_and_gpu_synchronization d ...
- 更改"xxxx" 的权限: 不允许的操作
[摘要:做为root用户,用chmod为何改没有了文件权限 以ROOT用户上岸,当用chmod改文件权限时,体系表现无权变动,为何 文件名是:aa chmod 777 aa chmod: changi ...