项目中登录验证码怎么做才合理

编程入门 行业动态 更新时间:2024-10-14 16:23:15

项目中登录验证码<a href=https://www.elefans.com/category/jswz/34/1769466.html style=怎么做才合理"/>

项目中登录验证码怎么做才合理

唠嗑部分

今天我们来聊聊项目实战中登录验证码如何做比较合理,首先我们聊以下几个问题

1、登录时验证码校验是否必要?

答案当然是很有必要的,因为用户登录行为会直接影响数据库,如果没有某些防范措施,有恶意用户暴力破解密码,那就十分严重了,验证码校验是防止接口被刷的一种方式,可以大大的降低接口请求的频率

还有一些系统会加入密码次数校验,当密码错误次数超过n次时,会锁定该用户,在指定时间段内不允许登录

除此之外,对于用户接口限流也是一种方案,小伙伴可以自行尝试

2、验证码校验是前端行为还是服务端行为?

两种方式均可以,区别如下

前端行为:仅能保证前端页面操作时验证的效果,不能够保证接口安全,用户可跳过页面直接访问服务端接口,不建议

服务端行为:能够保证登陆接口安全,限制用户登录频率,可配合用户ip流量限制、密码错误次数防范等措施,建议

3、生成验证码后,服务器应该存在什么地方,会有哪些问题?

在学习jsp+servlet时,用户信息通常会存入到服务端的session当中,验证码也可存入session,但是之针对单实例可行,如多实例,需实现session共享或配合ip_hash的规则

可存入分布式缓存中,不会有多实例问题、也不需要解决session共享的问题

4、如何实现分布式验证码校验,保证登录安全?

首先,服务端提供获取验证码的接口,出参包含key、code(code为实际验证码,key为Redis存储的key),返回验证码之前将验证码存入redis中

前端收到验证码后,采用canvas绘制验证码,用户手动输入验证码后,将用户名、密码、验证码、key传入服务端进行登录

服务端收到登录请求后,查询redis,跟用户输入的验证码进行比较,比较通过后进行登录

言归正传

验证码校验是用户登录的第一道屏障,未验证通过则不进行登录,不接触数据库

1、导入验证码依赖,其他依赖自行添加,需redis、hutool-all

<dependency><groupId>com.github.penggle</groupId><artifactId>kaptcha</artifactId><version>2.3.2</version>
</dependency>

2、配置kaptcha

/** @Project:cxs-currency-sys-server* @Author:cxs* @Motto:放下杂念,只为迎接明天更好的自己* */
@Configuration
public class KaptchaConfig {private static final String CHAR_STR = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";private static final String CHAR_LENGTH = "4";@Beanpublic Producer captcha() {// 配置图形验证码的基本参数Properties properties = new Properties();// 字符集properties.setProperty("kaptcha.textproducer.char.string", CHAR_STR);// 字符长度properties.setProperty("kaptcha.textproducer.char.length", CHAR_LENGTH);Config config = new Config(properties);DefaultKaptcha defaultKaptcha = new DefaultKaptcha();defaultKaptcha.setConfig(config);return defaultKaptcha;}
}

3、生成验证码核心代码

public void getValidateCode(BaseResult result) {long startTime = System.currentTimeMillis();try {// 创建验证码文本ValidateCodeVO vo = new ValidateCodeVO();String key = IdUtil.simpleUUID();String code = captchaProducer.createText();redisUtil.set(redisUtil.getCacheKey(CachePrefixContent.VALIDATE_CODE_PREFIX, key), code, commonConfig.getCodePeriod(), TimeUnit.SECONDS);vo.setKey(key);vo.setCode(code);result.setData(vo);} catch (Exception e) {log.error("生成验证码失败,{}", e);result.setCode(CurrencyErrorEnum.OPERA_ERROR.getCode());result.setMsg(CurrencyErrorEnum.OPERA_ERROR.getMsg());} finally {long endTime = System.currentTimeMillis();log.info("【{}】【生成验证码接口】【{}ms】 \n入参:{}\n出参:{}", "生成验证码", endTime - startTime, null, result);}}

4、接口出参预览

{"code": 200,"data": {"code": "2972","key": "a23030e821384684a47912fac215cfb1"},"msg": "操作成功"
}

5、前端实现主要代码(注意:登录框的部分代码)

<el-form-item prop="code"><el-row :gutter="20"><el-col :span="12"><el-input ref="code" type="text" prefix-icon="el-icon-key" v-model="userInfo.code" placeholder="验证码" name="code" tabindex="2" autocomplete="on" @keyup.enter.native="loginHandle"/></el-col><el-col :span="6" :offset="3"><canvas ref="canvas" :width="codeInfo.codeWidth" :height="codeInfo.codeHeight" @click="reloadCode"></canvas></el-col></el-row>
</el-form-item>

6、需要到的函数

// 创建验证码
async createdCode() {// 调用上述接口生成const res = await getValidateCode()const {code, data, msg} = resthis.userInfo.codeKey = data.keyconst identifyCode = data.codeconst codeList = identifyCode.split("");const canvas = this.$refs.canvas;// 获取 canvas 元素const ctx = canvas.getContext('2d');ctx.textBaseline = 'bottom';if (this.backgroundColor != '' && this.backgroundColor != null) {// 绘制画布背景颜色ctx.fillStyle = this.backgroundColor;} else {ctx.fillStyle = this.randomColor(255, 255);}ctx.fillRect(0, 0, this.contentWidth, this.contentHeight);codeList.forEach((code, i) => {// 绘制验证码字符this.drawText(ctx, code, i + 1, identifyCode.length);})this.drawLine(ctx);// 绘制干扰线this.drawDot(ctx);// 绘制干扰点},randomNum(min, max) {// 生成指定范围内的随机整数return Math.floor(Math.random() * (max - min) + min);},randomColor(min, max) {// 生成指定范围内的随机颜色const r = this.randomNum(min, max);const g = this.randomNum(min, max);const b = this.randomNum(min, max);return `rgb(${r},${g},${b})`;},drawText(ctx, txt, i, len) {// 绘制验证码字符ctx.fillStyle = this.randomColor(0, 160);ctx.font = `${this.randomNum(25, 30)}px SimHei`;const x = (i / (len + 1)) * 120;const y = this.randomNum(30, 35);const deg = this.randomNum(-45, 45);ctx.translate(x, y);ctx.rotate((deg * Math.PI) / 180);ctx.fillText(txt, 0, 0);ctx.rotate((-deg * Math.PI) / 180);ctx.translate(-x, -y);},drawLine(ctx) {// 绘制干扰线for (let i = 0; i < 5; i++) {ctx.strokeStyle = this.randomColor(100, 255);ctx.beginPath();ctx.moveTo(this.randomNum(0, 120), this.randomNum(0, 40));ctx.lineTo(this.randomNum(0, 120), this.randomNum(0, 40));ctx.stroke();}},drawDot(ctx) {// 绘制干扰点for (let i = 0; i < 80; i++) {ctx.fillStyle = this.randomColor(0, 255);ctx.beginPath();ctx.arc(this.randomNum(0, 120), this.randomNum(0, 40), 1, 0, 2 * Math.PI);ctx.fill();}},reloadCode() {// 点击按钮时清除画布并重新生成验证码const canvas = this.$refs.canvasconst ctx = canvas.getContext('2d')ctx.clearRect(0, 0, canvas.width, canvas.height)this.createdCode()},

7、效果展示

结语

1、验证码功能就实现了,快去给你的项目安排吧!

2、制作不易,一键三连再走吧,您的支持永远是我最大的动力!

更多推荐

项目中登录验证码怎么做才合理

本文发布于:2023-11-16 08:57:15,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1615139.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:怎么做   验证码   项目

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!