登录验证码高扩展性设计方案

登录验证码高扩展性建设方案

本文分享了一种登录验证码高扩展性的建设方案,通过工厂模式+策略模式,增强了验证码服务中验证码生成器、验证码存储器、验证码图片生成器的扩展性,实现了服务组件的多样化,降低了维护成本

  • 登录验证码高扩展性建设方案
  • 1、前言
  • 2、接口规范
  • 3、流程规范
  • 4、验证码的实际开发示范
  • 5、总结

1、前言

在进行登录时,无论是账号密码登录,还是第三方登录,总是需要输入验证码。

使用验证码可以进行人机判断,提高安全性,过滤恶性攻击。

验证码一般由一串随机字符组成,当然也存在多种生成方式。

验证码的展现方式有很多种,例如图片,语音,手机验证码。

验证码的存储方式有很多种,例如数据库、缓存、JVM本地内存。

验证码的存储又涉及到另一个问题,验证码唯一id如何生成,在分布式项目中,一般可以通过数据库自增序列、缓存自增序列、UUID、雪花算法等方式生成唯一id。

既然生成一个验证码有这么多种方法,那如何设计一种高扩展性的验证码服务架构,使得各个部分的组件可以自由替换呢?这就是本文需要解决的问题。

技术栈:SpringBoot,MySQL,Redis,zookeeper。

设计模式:策略模式。

2、接口规范

根据上述分析,我们需要分别实现验证码的生成、展示、id生成、存储的接口,一般验证码服务需要对外提供生成验证码和校验验证码的api,我们写在一个接口中,四个组件以内部接口类的形式进行开发。


/*** @version 1.0* @description 验证码接口* @date 2023/9/29 15:59*/
public interface CheckCodeService {// 生成验证码public CheckCodeResultDto generate(CheckCodeParamsDto checkCodeParamsDto);// 校验验证码public boolean verify(String key, String code);// 验证码生成器public interface CheckCodeGenerator{String generate(int length);}// 唯一id生成public interface KeyGenerator{String generate(String prefix);}// 验证码存储器public interface CheckCodeStore{void set(String key, String value, Integer expire);String get(String key);void remove(String key);}// 展示包装器public interface DisplayGenerate{String display(String code);}
}

3、流程规范

定义好接口规范后,我们需要对流程进行规范,正常流程是使用验证码生成器生成一个随机的验证码,使用id生成器生成一个唯一id,使用存储器存储验证码和id,以不同的展示方式包装验证码并返回。

此时我们还没有实际开发各个生成器模块,只是对流程进行规范,让不同的展示方法代码实现我们这个规范,所以这个应该通过抽象类的方式实现,各个生成器模块以注入的方式得到。


/*** @version 1.0* @description 验证码接口* @date 2023/9/29 15:59*/
public abstract class AbstractCheckCodeService implements CheckCodeService {// 验证码生成器protected CheckCodeGenerator checkCodeGenerator;// id生成器protected KeyGenerator keyGenerator;// 验证码存储器protected CheckCodeStore checkCodeStore;// 展示包装器protected DisplayGenerate displayGenerator;public abstract void  setCheckCodeGenerator(CheckCodeGenerator checkCodeGenerator);public abstract void  setKeyGenerator(KeyGenerator keyGenerator);public abstract void  setCheckCodeStore(CheckCodeStore CheckCodeStore);public abstract void  setDisplayGenerate(DisplayGenerate displayGenerate);// 生成验证码public GenerateResult generate(CheckCodeParamsDto checkCodeParamsDto,Integer code_length,String keyPrefix,Integer expire){//生成验证码String code = checkCodeGenerator.generate(code_length);//生成唯一idString key = keyGenerator.generate(keyPrefix);//存储验证码checkCodeStore.set(key,code,expire);//验证码展示方法String display = displayGenerator.display(code);//返回验证码生成结果GenerateResult generateResult = new GenerateResult();generateResult.setKey(key);generateResult.setCode(code);generateResult.setDisplay(display);return generateResult;}@Dataprotected class GenerateResult{String key;String code;String display;}public abstract CheckCodeResultDto generate(CheckCodeParamsDto checkCodeParamsDto);// 校验验证码public boolean verify(String key, String code){if (StringUtils.isBlank(key) || StringUtils.isBlank(code)){return false;}String code_l = checkCodeStore.get(key);if (code_l == null){return false;}boolean result = code_l.equalsIgnoreCase(code);if(result){//删除验证码checkCodeStore.remove(key);}return result;}
}

参数类


public class CheckCodeParamsDto {// 验证码展示类型private String checkCodeType;
}

4、验证码的实际开发示范

实际实现抽象类的方法需要完成四个组件的注入即可。


@Service("CheckCodeService")
public class CheckCodeServiceImpl extends AbstractCheckCodeService implements CheckCodeService {@Resource(name="NumberLetterCheckCodeGenerator")@Overridepublic void setCheckCodeGenerator(CheckCodeGenerator checkCodeGenerator) {this.checkCodeGenerator = checkCodeGenerator;}@Resource(name="UUIDKeyGenerator")@Overridepublic void setKeyGenerator(KeyGenerator keyGenerator) {this.keyGenerator = keyGenerator;}@Resource(name="MemoryCheckCodeStore")@Overridepublic void setCheckCodeStore(CheckCodeStore checkCodeStore) {this.checkCodeStore = checkCodeStore;}@Resource(name="PicCheckCodeGenerator")@Overridepublic void setDisplayGenerate(DisplayGenerator displayGenerator) {this.displayGenerator = displayGenerator;}@Overridepublic CheckCodeResultDto generate(CheckCodeParamsDto checkCodeParamsDto) {GenerateResult generate = generate(checkCodeParamsDto, 4, "checkcode:", 60);String key = generate.getKey();String code = generate.getCode();String display = generate.getDisplay();CheckCodeResultDto checkCodeResultDto = new CheckCodeResultDto();checkCodeResultDto.setDisplay(display);checkCodeResultDto.setKey(key);return checkCodeResultDto;}}

涉及的实体类


/*** @version 1.0* @description 验证码生成结果类* @date 2023/9/29 15:48*/
@Data
public class CheckCodeResultDto {// 验证码idprivate String key;// 展示方式private String display;
}

四个组件的实现示范:

验证码生成器:


@Component("NumberLetterCheckCodeGenerator")
public class NumberLetterCheckCodeGenerator implements CheckCodeService.CheckCodeGenerator {@Overridepublic String generate(int length) {String str="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";Random random=new Random();StringBuffer sb=new StringBuffer();for(int i=0;i<length;i++){int number=random.nextInt(36);sb.append(str.charAt(number));}return sb.toString();}
}

唯一id生成器(以UUID的方式生成)


@Component("UUIDKeyGenerator")
public class UUIDKeyGenerator implements CheckCodeService.KeyGenerator {@Overridepublic String generate(String prefix) {String uuid = UUID.randomUUID().toString();return prefix + uuid.replaceAll("-", "");}
}

验证码存储器(以Redis为例)


@Component("MemoryCheckCodeStore")
public class MemoryCheckCodeStore implements CheckCodeService.CheckCodeStore {@Autowiredpublic RedissonClient redissonClient;@Overridepublic void set(String key, String value, Integer expire) {if (get(key)!=null) log.error("codes key conflict");redisTemplate.opsForValue().set(key, value, 300 + new Random().nextInt(100), TimeUnit.SECONDS);}@Overridepublic String get(String key) {return (String) redisTemplate.opsForValue().get(key);}@Overridepublic void remove(String key) {boolean b = redisTemplate.opsForValue().getOperations().delete(key);if (!b) log.info("remove codes key failure");}
}

展示生成器(以图片为例)


@Component("PicCheckCodeGenerate")
public class PicCheckCodeGenerate implements CheckCodeService.DisplayGenerate {@Autowiredprivate DefaultKaptcha kaptcha;@Overrideprivate String display(String code) {// 生成图片验证码ByteArrayOutputStream outputStream = null;BufferedImage image = kaptcha.createImage(code);outputStream = new ByteArrayOutputStream();String imgBase64Encoder = null;try {// 对字节数组Base64编码BASE64Encoder base64Encoder = new BASE64Encoder();ImageIO.write(image, "png", outputStream);imgBase64Encoder = "data:image/png;base64," + EncryptUtil.encodeBase64(outputStream.toByteArray());} catch (IOException e) {e.printStackTrace();} finally {try {outputStream.close();} catch (IOException e) {e.printStackTrace();}}return imgBase64Encoder;}
}

5、总结

本文针对验证码生成过程节点多、实现方案多等特点,提出了一种高扩展性的建设方案,并给出了实际开发示例。

本文提出的验证码生成框架具有高扩展性,可以对任一组件进行创建开发、动态替换。如果结合Nacos和yaml,还可以实现组件热更新。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/366510.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

pytest-yaml-sanmu(五):跳过执行和预期失败

除了手动注册标记之外&#xff0c;pytest 还内置了一些标记可直接使用&#xff0c;每种内置标记都会用例带来不同的特殊效果&#xff0c;本文先介绍 3 种。 1. skip skip 标记通常用于忽略暂时无法执行&#xff0c;或不需要执行的用例。 pytest 在执行用例时&#xff0c;如果…

Redis 7.x 系列【14】数据类型之流(Stream)

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 本系列Redis 版本 7.2.5 源码地址&#xff1a;https://gitee.com/pearl-organization/study-redis-demo 文章目录 1. 概述2. 常用命令2.1 XADD2.2 XRANGE2.3 XREVRANGE2.4 XDEL2.5 XLEN2.6 XREAD2.7 XG…

【.Net】Web项目部署腾讯云

文章目录 总述前置准备docker-compose部署普通部署 参考 总述 前置准备 云服务添加端口 另有linux本身防火墙请参考&#xff1a; 【Linux】防火墙命令 需安装.Net SDK和Asp .Net Runtime 注意&#xff1a; 1、sdk也要不只是runtime 2、是Asp .Net Runtime不是.Net Runtime …

国产音频放大器工作原理以及应用领域

音频放大器是在产生声音的输出元件上重建输入的音频信号的设备&#xff0c;其重建的信号音量和功率级都要理想&#xff1a;如实、有效且失真低。音频范围为约20Hz&#xff5e;20000Hz&#xff0c;因此放大器在此范围内必须有良好的频率响应&#xff08;驱动频带受限的扬声器时要…

BIOS设置与系统分区

&#x1f4d1;打牌 &#xff1a; da pai ge的个人主页 &#x1f324;️个人专栏 &#xff1a; da pai ge的博客专栏 ☁️宝剑锋从磨砺出&#xff0c;梅花香自苦寒来 目录 一BIOS 1破解密码的前提 2B…

Spring Cloud Gateway3.x自定义Spring Cloud Loadbalancer负载均衡策略以及实现动态负载均衡策略的方案

目录 前言 1.原理分析 1.1 ReactiveLoadBalancerClientFilter源码分析 1.2 LoadBalancerClientFactory源码分析 2.代码实现 2.1 扩展原生RoundRobinLoadBalancer轮询策略 2.1.1 自定义实现RoundRobinLoadBalancer 2.1.2 配置自定义的RoundRobinLoadBalan…

【web3】分享一个web入门学习平台-HackQuest

前言 一直想进入web3行业&#xff0c;但是没有什么途径&#xff0c;偶然在电鸭平台看到HackQuest的共学营&#xff0c;发现真的不错&#xff0c;并且还接触到了黑客松这种形式。 链接地址&#xff1a;HackQuest 平台功能 学习路径&#xff1a;平台有完整的学习路径&#xff…

金蝶云星空字段之间连续触发值更新

文章目录 金蝶云星空字段之间连续触发值更新场景说明具体需求&#xff1a;解决方案 金蝶云星空字段之间连续触发值更新 场景说明 字段A配置了字段B的计算公式&#xff0c;字段B配置了自动C的计算公式&#xff0c;修改A的时候&#xff0c;触发了B的重算&#xff0c;但是C触发不…

ABeam×StartUp | ABeam德硕中国新创部门拜访通用机器人初创公司 :逐际动力,就具身智能机器人的发展展开交流

近日&#xff0c;ABeam中国新创部门有幸拜访了深圳逐际动力科技有限公司&#xff08;以下简称&#xff1a;逐际动力&#xff09;。作为一家通用机器人公司&#xff0c;其在人形机器人、四轮足机器人等领域具有深厚的学术与技术储备。 现场合影 左&#xff1a;ABeam中国新创部门…

最快33天录用!一投就中的医学4区SCI,几乎不退稿~

【SciencePub学术】今天小编给大家推荐2本生物医学领域的SCI&#xff0c;此期刊为我处目前合作的重点期刊&#xff01;影响因子0-3.0之间&#xff0c;最重要的是审稿周期较短&#xff0c;对急投的学者较为友好&#xff01; 医学医药类SCI 01 / 期刊概况 【期刊简介】IF&…

多模态融合 + 慢病精准预测

多模态融合 慢病精准预测 慢病预测算法拆解子解法1&#xff1a;多模态数据集成子解法2&#xff1a;实时数据处理与更新子解法3&#xff1a;采用大型语言多模态模型&#xff08;LLMMs&#xff09;进行深度学习分析 慢病预测更多模态 论文&#xff1a;https://arxiv.org/pdf/2406…

高通骁龙(Qualcomm Snapdragon)CDSP HVX HTP 芯片简介与开发入门

1. Hexagon DSP/HVX/HTP 硬件演进 说到高通骁龙芯片大家应该不会陌生&#xff0c;其作为最为广泛的移动处理器之一&#xff0c;几乎每一个品牌的智能手机都会使用高通骁龙的处理器。 高通提供了一系列骁龙芯片解决方案。根据性能强弱分为了5个产品系列&#xff1a;从最高端的…

数据结构_1.0

一、数据结构概述 1.1 概念 在计算机科学中&#xff0c;数据结构是一种数据组织、管理和存储的格式 。它是相互之间存在一种或多种特定关系的数据元素的集合。通常情况下&#xff0c;精心选择的数据结构可以带来更高的运行或者存储效率。数据结构往往同高效的检索算法和索引技…

【C语言】typedef 关键字

在C语言中&#xff0c;typedef关键字用于给现有的数据类型起一个新的名字。它在提高代码可读性、简化复杂类型声明、增强可维护性方面非常有用。typedef通常用于定义结构体、指针、函数指针以及其他复杂类型。 基本用法 typedef int MyInt; MyInt x 10;在这个例子中&#xf…

wps linux node.js 加载项开发,和离线部署方案

环境准备 windwos 安装node.js 安装VSCode 安装wps linux 安装node.js 安装VSCode 安装wps 通过npm 安装wpsjs SDK 使用npm安装wpsjs npm install -g wpsjs 创建一个项目 wpsjs create WPS-Addin-PPT 创建项目会让你选择2个东西&#xff1a; 1&#xff1a;选择你的文…

SpringBoot实现图片添加水印(完整)

提示&#xff1a;昨天不是写了一个类似与图片添加水印的版本吗,今天来写一个带数据库&#xff0c;并且可以完整访问的版本 文章目录 目录 文章目录 引入库 配置文件 数据库配置 字段配置 索引配置 数据库表语句 启动文件 前端代码 整体代码目录 配置类AppConfig Contro…

五千元软考补贴,这个地区的人别错过!

软考合格者可享受一些补贴&#xff0c;最高可达25万&#xff1f;&#xff01;持有软考证书可领取哪些补贴&#xff1f;软考补贴详细信息 由于不同地区政策有时间限制&#xff0c;符合条件的人员应尽快领取哦~ 今天继续分享常德地区的补贴信息。 这里给大家总结一下和软考有关…

Java的日期类常用方法

Java_Date 第一代日期类 获取当前时间 Date date new Date(); System.out.printf("当前时间" date); 格式化时间信息 SimpleDateFormat simpleDateFormat new SimpleDateFormat("yyyy-mm-dd hh:mm:ss E); System.out.printf("格式化后时间" si…

ROS2 RQT

1. RQT是什么 RQT是一个GUI框架&#xff0c;通过插件的方式实现了各种各样的界面工具。 强行解读下&#xff1a;RQT就像插座&#xff0c;任何电器只要符合插座的型号就可以插上去工作。 2.选择插件 这里我们可以选择现有的几个RQT插件来试一试&#xff0c;可以看到和话题、参…