在介绍之前,首先一个概念明确一个共识:没有攻不破的网站,只有值不值得。
这意思是说,我们可以尽可能的提高自己网站的安全,但并没有绝对的安全,当网站安全级别大于攻击者能得到的回报时,你的网站就是安全的。
所以百度搜到的很多验证码都已经结合了人工智能分析用户行为,很厉害。但这里只介绍我的小网站是怎么设计的。
大概逻辑:当需要验证码时,前端发送ajax向后台请求相关数据发送回前端,由前端生成(与后端生成图片,然后传送图片到前端的做法相比安全性要差很多。但也是可以预防的,后端可以对此Session进行请求记录,如果在一定时间内恶意多次请求,可以进行封禁ip等对策),验证完成后,后台再对传回的数据进行校验。
效果图:
1|0js类的设计:
1.定义一个验证码父类,因为目前只有这一个验证类型,倘若以后再要扩展其他验证类型呢。那么它们之间肯定有很多公共之处(如:验证成功、失败的回调,获取验证码的类型,获取验证结果等),所以这些共同点可以提炼出来,下面是我目前的父类样子:
/** * 验证码的父类,所有验证码都要继承这个类 * @param id 验证码的唯一标识 * @param type 验证码的类型 * @param contentDiv 包含着验证码的DIV * @constructor */ var Identifying = function (id,type,contentDiv){ this.id = id; this.type = type; this.contentDiv=contentDiv; } /** * 销毁函数 */ Identifying.prototype.destroy = function(){ this.successFunc = null; this.errorFunc = null; this.clearDom(); this.contentDiv = null; } /** * 清除节点内容 */ Identifying.prototype.clearDom = function(){ if(this.contentDiv instanceof jQuery){ this.contentDiv.empty(); }else if(this.contentDiv instanceof HTMLElement){ this.contentDiv.innerText = ""; } } /** * 回调函数 * 验证成功后进行调用 * this需要指具体验证类 * @param result 对象,有对应验证类的传递的参数,具体要看验证类 */ Identifying.prototype.success = function (result) { if(this.successFunc instanceof Function){ this.successFunc(result); } } /** * 验证失败发生错误调用的函数 * @param result */ Identifying.prototype.error = function (result) { if(this.errorFunc instanceof Function){ this.errorFunc(result); }else{ //统一处理错误 } } /** * 获取验证码id */ Identifying.prototype.getId = function () { return this.id; } /** * 获取验证码类型 * @returns {*} */ Identifying.prototype.getType = function () { return this.type; } /** * 显示验证框 */ Identifying.prototype.showIdentifying = function(callback){ this.contentDiv.show(null,callback); } /** * 隐藏验证框 */ Identifying.prototype.hiddenIdentifying = function(callback){ this.contentDiv.hide(null,callback); } /** * 获得验证码显示的dom元素 */ Identifying.prototype.getContentDiv = function () { return this.contentDiv; }
然后,滑动验证码类继承此父类(js继承会单独写篇文章),滑动验证码类如下:
/** * 滑动验证类 * complete传递的参数为identifyingId,identifyingType,moveEnd_X * @param config 各种配置 */ var ImgIdentifying = function(config) { Identifying.call(this, config.identifyingId, config.identifyingType,config.el); this.config = config; this.init(); this.showIdentifying(); } //继承父类 extendClass(Identifying, ImgIdentifying); /** * 销毁函数 */ ImgIdentifying.prototype.destroy = function () { Identifying.prototype.destroy.call(this); } var width = '260'; var height = '116'; var pl_size = 48; var padding_ = 20; ImgIdentifying.prototype.init = function () { this.clearDom(); var el = this.getContentDiv(); var w = width; var h = height; var PL_Size = pl_size; var padding = padding_; var self = this; //这个要转移到后台 function RandomNum(Min, Max) { var Range = Max - Min; var Rand = Math.random(); if (Math.round(Rand * Range) == 0) { return Min + 1; } else if (Math.round(Rand * Max) == Max) { return Max - 1; } else { var num = Min + Math.round(Rand * Range) - 1; return num; } } //确定图片 var imgSrc = this.config.img; var X = this.config.X; var Y = this.config.Y; var left_Num = -X + 10; var html = '<div style="position:relative;padding:16px 16px 28px;border:1px solid #ddd;background:#f2ece1;border-radius:16px;">'; html += '<div style="position:relative;overflow:hidden;width:' + w + 'px;">'; html += '<div style="position:relative;width:' + w + 'px;height:' + h + 'px;">'; html += '<img id="scream" src="/UploadFiles/2021-04-02/' + imgSrc + '">其中init的方法,大家就可以抄啦,验证码是这里生成的(感谢网上一些热心网友提供的Mod,在此基础上改的)。
2|0后端的设计:
首先要有一个验证码的接口,将一些常量和共同的方法抽象到接口中(接口最重要的作用就是行为的统一,意思是我如果知道这个是验证码,那么必定就会有验证的方法,不管它是滑动验证,图形验证等,然后就可以放心的调用验证方法去获取验证结果,下面过滤器设计就可以立马看到这作用。具体java接口的说明会单独写篇文章),接口如下:
/** * 验证码类的接口,所有验证码必须继承此接口 */ public interface I_Identifying<T> { String EXCEPTION_CODE = SystemStaticValue.IDENTIFYING_EXCEPTION_CODE; String IDENTIFYING = "Identifying"; //--------------以下为验证码大体错误类型,抛出错误时候用,会传至前端--------------- //验证成功 String SUCCESS = "Success"; //验证失败 String FAILURE = "Failure"; //验证码过期 String OVERDUE = "Overdue"; //-------以下为验证码具体错误类型,存放在checkResult------------- String PARAM_ERROR = "验证码参数错误"; String OVERDUE_ERROR = "验证码过期"; String TYPE_ERROR = "验证码业务类型错误"; String ID_ERROR = "验证码id异常"; String CHECK_ERROR = "验证码验证异常"; /** * 获取生成好的验证码 * @param request * @return */ public T getInstance(HttpServletRequest request) throws Exception; /** * 进行验证,没抛异常说明验证无误 * @return */ public void checkIdentifying(HttpServletRequest request) throws Exception; /** * 获取验证结果,如果成功则为success,失败则为失败信息 * @return */ public String getCheckResult(); /** * 获取验证码的业务类型 * @return */ public String getIdentifyingType(); }然后,设计一个具体的滑动验证类去实现这个接口,这里只贴参数:
/** * @author NiceBin * @description: 验证码类,前端需要生成验证码的信息 * @date 2019/7/12 16:04 */ public class ImgIdentifying implements I_Identifying<ImgIdentifying>,Serializable { //此次验证码的id private String identifyingId; //此次验证码的业务类型 private String identifyingType; //需要使用的图片 private String imgSrc; //生成块的x坐标 private int X; //生成块的y坐标 private int Y; //允许的误差 private int deviation = 2; //验证码生成的时间 private Calendar calendar; //验证码结果,如果有结果说明已经被校验,防止因为网络延时的二次校验 private String checkResult; //下面是逻辑代码... }上面每个变量都是一种校验手段,如calendar可以检验验证码是否过期,identifyingType检验此验证码是否是对应的业务等。每多想一点,别人破解就多费劲一点。
后端验证码的验证是不需要具体的类去调用的,而是被一个过滤器统一过滤,才过滤器注册的时候,将需要进行验证的路径写进去即可,过滤器代码如下:
r NiceBin * @description: 验证码过滤器,帮忙验证有需要验证码的请求,不帮忙生成验证码 * @date 2019/7/23 15:06 */ @Component public class IdentifyingInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request.getSession(); I_Identifying identifying= (I_Identifying)session.getAttribute(I_Identifying.IDENTIFYING); if(identifying!=null){ identifying.checkIdentifying(request); }else { //应该携带验证码信息的,结果没有携带,那就是个非法请求 return false; } return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } }可以看到接口的用处了,之前在用户申请验证码时,验证码类是放到用户session中的,所以这里直接取出调用checkIdentifying即可,不需要关系它到底是滑动验证码,还是图片验证码什么的。
总结
以上所述是小编给大家介绍的滑动验证码的设计与理解,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!
滑动验证码的实现
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。
更新日志
- 小骆驼-《草原狼2(蓝光CD)》[原抓WAV+CUE]
- 群星《欢迎来到我身边 电影原声专辑》[320K/MP3][105.02MB]
- 群星《欢迎来到我身边 电影原声专辑》[FLAC/分轨][480.9MB]
- 雷婷《梦里蓝天HQⅡ》 2023头版限量编号低速原抓[WAV+CUE][463M]
- 群星《2024好听新歌42》AI调整音效【WAV分轨】
- 王思雨-《思念陪着鸿雁飞》WAV
- 王思雨《喜马拉雅HQ》头版限量编号[WAV+CUE]
- 李健《无时无刻》[WAV+CUE][590M]
- 陈奕迅《酝酿》[WAV分轨][502M]
- 卓依婷《化蝶》2CD[WAV+CUE][1.1G]
- 群星《吉他王(黑胶CD)》[WAV+CUE]
- 齐秦《穿乐(穿越)》[WAV+CUE]
- 发烧珍品《数位CD音响测试-动向效果(九)》【WAV+CUE】
- 邝美云《邝美云精装歌集》[DSF][1.6G]
- 吕方《爱一回伤一回》[WAV+CUE][454M]