关系经济人类预测化学自然
中准网
自然科学
知识物理
化学生物
地理解释
预测理解
本质社会
人类现象
行为研究
经济政治
心理结构
关系指导
人文遗产

看起来高大上的滑块验证码是怎样实现的?

8月20日 火云谷投稿
  前言
  嗨,大家好,我是希留。
  验证码一直是各类网站登录和注册的一种校验方式,是用来防止有人恶意使用脚本批量进行操作从而设置的一种安全保护方式。随着近几年技术的发展,人们对于系统安全性和用户体验的要求越来越高,大多数网站系统都逐渐采用行为验证码来代替传统的图片验证码。
  今天这篇文章就来记录一下,我是如何实现从前端、到后端校验的整个流程的。一、实现效果
  无图无真相,实现的效果如下图所示,点击登录后弹出一个弹出层,拼图是由后端生成的,拖动滑块位置,后端校验是否已拖动到指定的位置。
  二、实现思路
  整体的实现思路如下:1、从服务器随机取一张底透明有形状的模板图,再随机取一张背景图、2、随机生成抠图块坐标3、根据步骤2的坐标点,对背景大图的抠图区域的颜色进行处理,新建的图像根据轮廓图颜色赋值,背景图生成遮罩层。4、完成以上步骤之后得到两张图(扣下来的方块图,带有抠图区域阴影的原图),将这两张图和抠图区域的y坐标传到前台,x坐标存入redis。5、前端在移动拼图时将滑动距离x坐标参数请求后台验证,服务器根据redis取出x坐标与参数的x进行比较,如果在伐值内则验证通过。如果滑动不成功,自动刷新图片,重置拼图,滑动成功,且账号密码正确就直接跳转到首页。三、实现步骤1。后端java代码1。1新建一个拼图验证码类
  代码如下(示例):DatapublicclassCaptcha{随机字符串privateStringnonceS验证值privateS生成的画布的base64privateStringcanvasS画布宽度privateIntegercanvasW画布高度privateIntegercanvasH生成的阻塞块的base64privateStringblockS阻塞块宽度privateIntegerblockW阻塞块高度privateIntegerblockH阻塞块凸凹半径privateIntegerblockR阻塞块的横轴坐标privateIntegerblockX;阻塞块的纵轴坐标privateIntegerblockY;图片获取位置privateI}1。2新建一个拼图验证码工具类
  代码如下(示例):publicclassCaptchaUtils{网络图片地址privatefinalstaticStringIMGURLhttps:loyer。wangviewftpwallpapers。本地图片地址privatefinalstaticStringIMGPATHE:Tempwallpapers。入参校验设置默认值publicstaticvoidcheckCaptcha(Captchacaptcha){设置画布宽度默认值if(captcha。getCanvasWidth()null){captcha。setCanvasWidth(320);}设置画布高度默认值if(captcha。getCanvasHeight()null){captcha。setCanvasHeight(155);}设置阻塞块宽度默认值if(captcha。getBlockWidth()null){captcha。setBlockWidth(65);}设置阻塞块高度默认值if(captcha。getBlockHeight()null){captcha。setBlockHeight(55);}设置阻塞块凹凸半径默认值if(captcha。getBlockRadius()null){captcha。setBlockRadius(9);}设置图片来源默认值if(captcha。getPlace()null){captcha。setPlace(0);}}获取指定范围内的随机数publicstaticintgetNonceByRange(intstart,intend){RandomrandomnewRandom();returnrandom。nextInt(endstart1)}获取验证码资源图publicstaticBufferedImagegetBufferedImage(Integerplace){try{随机图片intnoncegetNonceByRange(0,1000);获取网络资源图片if(0place){StringimgUrlString。format(IMGURL,nonce);URLurlnewURL(imgUrl);returnImageIO。read(url。openStream());}获取本地图片else{StringimgPathString。format(IMGPATH,nonce);FilefilenewFile(imgPath);returnImageIO。read(file);}}catch(Exceptione){System。out。println(获取拼图资源失败);异常处理}}调整图片大小publicstaticBufferedImageimageResize(BufferedImagebufferedImage,intwidth,intheight){ImageimagebufferedImage。getScaledInstance(width,height,Image。SCALESMOOTH);BufferedImageresultImagenewBufferedImage(width,height,BufferedImage。TYPEINTARGB);Graphics2Dgraphics2DresultImage。createGraphics();graphics2D。drawImage(image,0,0,null);graphics2D。dispose();returnresultI}抠图,并生成阻塞块publicstaticvoidcutByTemplate(BufferedImagecanvasImage,BufferedImageblockImage,intblockWidth,intblockHeight,intblockRadius,intblockX,intblockY){BufferedImagewaterImagenewBufferedImage(blockWidth,blockHeight,BufferedImage。TYPE4BYTEABGR);阻塞块的轮廓图int〔〕〔〕blockDatagetBlockData(blockWidth,blockHeight,blockRadius);创建阻塞块具体形状for(inti0;iblockWi){for(intj0;jblockHj){try{原图中对应位置变色处理if(blockData〔i〕〔j〕1){背景设置为黑色waterImage。setRGB(i,j,Color。BLACK。getRGB());blockImage。setRGB(i,j,canvasImage。getRGB(blockXi,blockYj));轮廓设置为白色,取带像素和无像素的界点,判断该点是不是临界轮廓点if(blockData〔i1〕〔j〕0blockData〔i〕〔j1〕0blockData〔i1〕〔j〕0blockData〔i〕〔j1〕0){blockImage。setRGB(i,j,Color。WHITE。getRGB());waterImage。setRGB(i,j,Color。WHITE。getRGB());}}这里把背景设为透明else{blockImage。setRGB(i,j,Color。TRANSLUCENT);waterImage。setRGB(i,j,Color。TRANSLUCENT);}}catch(ArrayIndexOutOfBoundsExceptione){防止数组下标越界异常}}}在画布上添加阻塞块水印addBlockWatermark(canvasImage,waterImage,blockX,blockY);}构建拼图轮廓轨迹privatestaticint〔〕〔〕getBlockData(intblockWidth,intblockHeight,intblockRadius){int〔〕〔〕datanewint〔blockWidth〕〔blockHeight〕;doublepoMath。pow(blockRadius,2);随机生成两个圆的坐标,在4个方向上随机找到2个方向添加凸凹凸凹1intface1RandomUtils。nextInt(0,4);凸凹2intface2;保证两个凸凹不在同一位置do{face2RandomUtils。nextInt(0,4);}while(face1face2);获取凸凹起位置坐标int〔〕circle1getCircleCoords(face1,blockWidth,blockHeight,blockRadius);int〔〕circle2getCircleCoords(face2,blockWidth,blockHeight,blockRadius);随机凸凹类型intshapegetNonceByRange(0,1);圆的标准方程(xa)(yb)r,标识圆心(a,b),半径为r的圆计算需要的小图轮廓,用二维数组来表示,二维数组有两张值,0和1,其中0表示没有颜色,1有颜色for(inti0;iblockWi){for(intj0;jblockHj){data〔i〕〔j〕0;创建中间的方形区域if((iblockRadiusiblockWidthblockRadiusjblockRadiusjblockHeightblockRadius)){data〔i〕〔j〕1;}doubled1Math。pow(iObjects。requireNonNull(circle1)〔0〕,2)Math。pow(jcircle1〔1〕,2);doubled2Math。pow(iObjects。requireNonNull(circle2)〔0〕,2)Math。pow(jcircle2〔1〕,2);创建两个凸凹if(d1pod2po){data〔i〕〔j〕}}}}根据朝向获取圆心坐标privatestaticint〔〕getCircleCoords(intface,intblockWidth,intblockHeight,intblockRadius){上if(0face){returnnewint〔〕{blockWidth21,blockRadius};}左elseif(1face){returnnewint〔〕{blockRadius,blockHeight21};}下elseif(2face){returnnewint〔〕{blockWidth21,blockHeightblockRadius1};}右elseif(3face){returnnewint〔〕{blockWidthblockRadius1,blockHeight21};}}在画布上添加阻塞块水印privatestaticvoidaddBlockWatermark(BufferedImagecanvasImage,BufferedImageblockImage,intx,inty){Graphics2Dgraphics2DcanvasImage。createGraphics();graphics2D。setComposite(AlphaComposite。getInstance(AlphaComposite。SRCATOP,0。8f));graphics2D。drawImage(blockImage,x,y,null);graphics2D。dispose();}BufferedImage转BASE64publicstaticStringtoBase64(BufferedImagebufferedImage,Stringtype){try{ByteArrayOutputStreambyteArrayOutputStreamnewByteArrayOutputStream();ImageIO。write(bufferedImage,type,byteArrayOutputStream);Stringbase64Base64。getEncoder()。encodeToString(byteArrayOutputStream。toByteArray());returnString。format(data:base64,s,type,base64);}catch(IOExceptione){System。out。println(图片资源转换BASE64失败);异常处理}}}1。3新建一个service类
  代码如下(示例):ServicepublicclassCaptchaService{拼图验证码允许偏差privatestaticIntegerALLOWDEVIATION3;AutowiredprivateStringRedisTemplatestringRedisT校验验证码paramimageKeyparamimageCodereturnbooleanpublicStringcheckImageCode(StringimageKey,StringimageCode){ValueOperationsString,StringopsstringRedisTemplate。opsForValue();Stringtextops。get(imageCode:imageKey);if(StrUtil。isBlank(text)){return验证码已失效;}根据移动距离判断验证是否成功if(Math。abs(Integer。parseInt(text)Integer。parseInt(imageCode))ALLOWDEVIATION){return验证失败,请控制拼图对齐缺口;}}缓存验证码,有效期15分钟paramkeyparamcodepublicvoidsaveImageCode(Stringkey,Stringcode){ValueOperationsString,StringopsstringRedisTemplate。opsForValue();ops。set(imageCode:key,code,15,TimeUnit。MINUTES);}获取验证码拼图(生成的抠图和带抠图阴影的大图及抠图坐标)publicObjectgetCaptcha(Captchacaptcha){参数校验CaptchaUtils。checkCaptcha(captcha);获取画布的宽高intcanvasWidthcaptcha。getCanvasWidth();intcanvasHeightcaptcha。getCanvasHeight();获取阻塞块的宽高半径intblockWidthcaptcha。getBlockWidth();intblockHeightcaptcha。getBlockHeight();intblockRadiuscaptcha。getBlockRadius();获取资源图BufferedImagecanvasImageCaptchaUtils。getBufferedImage(captcha。getPlace());调整原图到指定大小canvasImageCaptchaUtils。imageResize(canvasImage,canvasWidth,canvasHeight);随机生成阻塞块坐标intblockXCaptchaUtils。getNonceByRange(blockWidth,canvasWidthblockWidth10);intblockYCaptchaUtils。getNonceByRange(10,canvasHeightblockHeight1);阻塞块BufferedImageblockImagenewBufferedImage(blockWidth,blockHeight,BufferedImage。TYPE4BYTEABGR);新建的图像根据轮廓图颜色赋值,源图生成遮罩CaptchaUtils。cutByTemplate(canvasImage,blockImage,blockWidth,blockHeight,blockRadius,blockX,blockY);移动横坐标StringnonceStrUUID。randomUUID()。toString()。replaceAll(,);缓存saveImageCode(nonceStr,String。valueOf(blockX));设置返回参数captcha。setNonceStr(nonceStr);captcha。setBlockY(blockY);captcha。setBlockSrc(CaptchaUtils。toBase64(blockImage,png));captcha。setCanvasSrc(CaptchaUtils。toBase64(canvasImage,png));}}1。4新建一个controller类
  代码如下(示例):RestControllerRequestMapping(captcha)publicclassCaptchaController{AutowiredprivateCaptchaServicecaptchaSApiOperation(value生成验证码拼图)PostMapping(getcaptcha)publicRgetCaptcha(RequestBodyCaptchacaptcha){returnR。ok(captchaService。getCaptcha(captcha));}}1。5登录接口
  代码如下(示例):ApiOperation(value登录)PostMapping(valuelogin)publicRlogin(RequestBodyLoginVologinVo){只有开启了验证码功能才需要验证if(needAuthCode){StringmsgcaptchaService。checkImageCode(loginVo。getNonceStr(),loginVo。getValue());if(StringUtils。isNotBlank(msg)){returnR。error(msg);}}StringtokenloginService。login(loginVo。getUserName(),loginVo。getPassWord());if(StringUtils。isBlank(token)){returnR。error(用户名或密码错误);}MapString,StringtokenMapnewHashMap();tokenMap。put(token,token);tokenMap。put(tokenHead,tokenHead);returnR。ok(tokenMap);}2。前端vue代码2。1新建一个sliderVerify组件
  代码如下(示例):template!图片加载遮蔽罩!认证成功后的文字提示{{successHint}}!刷新按钮!前端生成templatevifisFrontCheck!验证图片canvasrefcanvasclassslidecanvas:widthcanvasWidth:heightcanvasHeight!阻塞块canvasrefblockclassslideblock:widthcanvasWidth:heightcanvasHeighttemplate!后端生成templatevelse!验证图片imgrefcanvasclassslidecanvas:widthcanvasWidth:heightcanvasHeight!阻塞块imgrefblock:class〔slideblock,{verifyfail:verifyFail}〕template!滑动条!滑块!按钮!按钮图标!滑动条提示文字spanclasssliderhint{{sliderHint}}spantemplatestylescoped。slideverify{position:}图片加载样式。imgloading{position:top:0;right:0;left:0;bottom:0;zindex:999;animation:loading1。5backgroundimage:url(。。。。assetsimagesloading。svg);backgroundrepeat:backgroundposition:backgroundsize:100backgroundcolor:737c8e;borderradius:5}keyframesloading{0{opacity:。7;}100{opacity:9;}}认证成功后的文字提示。successhint{position:top:0;right:0;left:0;zindex:999;display:alignitems:justifycontent:background:rgba(255,255,255,0。8);color:2CD000;fontsize:}刷新按钮。refreshicon{position:right:0;top:0;width:35height:35cursor:background:url(。。。。assetsimageslight。png)0432backgroundsize:35px470}验证图片。slidecanvas{borderradius:5}阻塞块。slideblock{position:left:0;top:0;}校验失败时的阻塞块样式。slideblock。verifyfail{transition:left0。5}滑动条。slider{position:textalign:width:100;height:40lineheight:40margintop:15background:f7f9color:45494c;border:1pxsolide4e7borderradius:5}滑动盒子。sliderbox{position:left:0;top:0;height:40border:0solid1991FA;background:D1E9FE;borderradius:5}滑动按钮。sliderbutton{position:top:0;left:0;width:40height:40background:boxshadow:003pxrgba(0,0,0,0。3);cursor:transition:background。2borderradius:5}鼠标悬浮时的按钮样式。sliderbutton:hover{background:1991FA}鼠标悬浮时的按钮图标样式。sliderbutton:hover。sliderbuttonicon{backgroundposition:013px}滑动按钮图标。sliderbuttonicon{position:top:15left:13width:15height:13background:url(。。。。assetsimageslight。png)026backgroundsize:35px470px}校验时的按钮样式。verifyactive。sliderbutton{height:38top:1border:1pxsolid1991FA;}校验时的滑动箱样式。verifyactive。sliderbox{height:38borderwidth:1}校验成功时的滑动箱样式。verifysuccess。sliderbox{height:38border:1pxsolid52CCBA;backgroundcolor:D2F4EF;}校验成功时的按钮样式。verifysuccess。sliderbutton{height:38top:1border:1pxsolid52CCBA;backgroundcolor:52CCBA!}校验成功时的按钮图标样式。verifysuccess。sliderbuttonicon{backgroundposition:00!}校验失败时的滑动箱样式。verifyfail。sliderbox{height:38border:1pxsolidf57a7a;backgroundcolor:fce1e1;transition:width0。5}校验失败时的按钮样式。verifyfail。sliderbutton{height:38top:1border:1pxsolidf57a7a;backgroundcolor:f57a7a!transition:left0。5}校验失败时的按钮图标样式。verifyfail。sliderbuttonicon{top:14backgroundposition:082px!}校验状态下的提示文字隐藏。verifyactive。sliderhint,。verifysuccess。sliderhint,。verifyfail。sliderhint{display:}style2。2在登录页使用滑块组件
  代码如下(示例):templateelformrefloginForm:modelloginForm:rulesloginRulesclassloginformautocompleteonlabelpositionleft。。。省略无关代码!滑块验证eldialogtitle请拖动滑块完成拼图width360px:visible。syncisShowSliderVerify:closeonclickmodalfalseclosedrefreshappendtobodysliderverifyrefsliderVerifysuccessonSuccessfailonFailagainonAgaineldialogelbutton:loadingloadingroundstylewidth:100;marginbottom:30click。native。preventhandleLogin登录elbuttonelformtemplate总结
  好了,以上就是本文的全部内容了,感谢大家的阅读。
  若觉得本文对你有帮助的话,还不忘点赞评论支持一下,感谢
投诉 评论 转载

散文欣赏再美的风景,都不及故乡的一草一木,一屋一巷再美的风景,都不及故乡的一草一木,一屋一巷女儿说两年多没回老家了,想回去看看。于是,昨天傍晚一家人驱车回乡。竟然迷路几次,也是够可以的,自嘲一下。一路前行,晚……小行星有多大据美国趣味科学网站3月6日报道,小行星一直在我们的太阳系周围盘旋,有时撞向包括地球在内的行星。然而,并非所有小行星都是行星杀手。虽然有些小行星体积巨大,但其他一些相当小巧。那么……西甲双雄齐开花,巴萨杠杠引援颇有成效,皇马真神本泽马力挽狂澜最近一轮西甲联赛上,巴萨和皇马都展现出了联赛头部球队的统治力,巴萨最近几个赛季状态低迷的情况下开启多次杠杆交易来断臂求生,在今夏引入了莱万、孔德、拉菲尼亚等一众顶级球星,从目前……看起来高大上的滑块验证码是怎样实现的?前言嗨,大家好,我是希留。验证码一直是各类网站登录和注册的一种校验方式,是用来防止有人恶意使用脚本批量进行操作从而设置的一种安全保护方式。随着近几年技术的发展,人们……苹果限制ChatGPT相关应用更新!果粉之家,专业苹果手机技术研究十年!您身边的苹果专家自2023年以来,OpenAI公司开发的人工智能ChatGPT就火遍全网,它可以根据用户输入的文本生成自然和流畅的回复……高黎贡山生命的博物馆(关注保护生物多样性)高黎贡山风光。杜小红摄高黎贡山下的山村。艾怀森摄高黎贡,绿色的净土,多少回白云停在天空,守望你不曾离去。传唱在高黎贡山脉两侧的民歌,记录了这片美丽土地上的动人故事。……大一女生在旅游公司实习每天剥百斤玉米?当事人有误解7月11日,一则女生旅游公司实习每天剥百斤玉米的视频新闻在网上掀起热议,视频内容大致为:近日,浙江宁波的大一女生顾同学暑假去旅游公司实习,结果每天都在剥玉米。顾同学剥的玉……花开四季,香飘四野!宝山这个新晋网红村你打卡过吗?中秋小假期找一处亲近自然的郊野乡村游玩吧去宝山新晋网红村花红村这里有春桃、夏棉、秋稻、冬梅四季风光足不出沪身边就是风景……家长应如何应对孩子的在网上看到这样一条热点新闻:十岁幼童成绩优秀却觉得父母不配拥有他这么聪明的孩子。原因是父母没有经济能力供养他上更好的学校和出国旅游以及更高物质的消费。看后,让人不觉冷汗直流,到……短裙长靴最近气温下降,很多人出门都换上了厚衣服,闺蜜今天出门穿了一身黑白相间的格子套装,显得身材苗条了好多,这身着装显得人气质提升了许多,既不是那么呆板,也显得活泼了许多,这个裙子也还……税收改革这十年财务的双卡税月2022年将召开中国共产党第二十次全国代表大会,税务总局组织开展回眸税收这十年献礼党的二十大短视频征集活动,今天发布:财务的双卡税月。吴圯业(厦门智能家电厂商财务总监):……一起去看流星雨!年底最精彩天象之一,就在这一天在即将到来的12月,火星冲日、双子座流星雨天象将先后亮相天宇。记者从北京天文馆获悉,12月首先登场的精彩天象就是8日的火星冲日。当天火星亮度1。8等,在深夜的星空中,其亮度仅次……
我的好朋友传奇3怀旧版重燃玛法神舰跑船天气元素系统,风云再起决战沙城冬奥会花滑天才朱易放弃美国国籍回归中国,获唯一冬奥女单资格玩具熊的五夜后宫电影定档10月27日北美上映正常人补充维生素剂量感人肺腑的话老年人降糖千万别忘护心脑出国旅游,遭遇国外APP不能安装?试试华为手机的出境易,有惊崇高造句用崇高造句大全生活因逗笑而精彩洗脸巾和餐巾纸有什么区别洗脸巾洗脸对皮肤好吗咸鸭蛋要裹多少盐腌蛋的门路你知道多少
攀龙附凤成语造句参考孩子的性教育到底该怎么说充气床怎么样产前阵痛是什么样子的97年南航空难录音,97南航5。8空难真相大曝光关于教师节的作文初一教师节演讲稿苹果村的日日夜夜,真正的果粉不是忠实的消费者发现公园的井盖有隐患怎么办【青年社会责任家】CYCAN和他的青年们视觉秀出产业与视觉盛宴幽默短语穆勒鞋怎么穿好看脚感超好的懒人鞋

友情链接:中准网聚热点快百科快传网快生活快软网快好知文好找菏泽德阳山西湖州宝鸡上海茂名内江三亚信阳长春北海西安安徽黄石烟台沧州湛江肇庆鹤壁六安韶关成都钦州