您现在的位置是:IT资讯 >>正文
基于 Kaptcha 实现分布式验证码登录
IT资讯29人已围观
简介前言为了防止验证系统被暴力破解,很多系统都增加了验证码效验,比较常见的就是图片二维码,业内比较安全的是短信验证码,当然还有一些拼图验证码,加入人工智能的二维码等等,我们今天的主题就是前后端分离的图片二 ...
前言
为了防止验证系统被暴力破解,基于很多系统都增加了验证码效验,现分比较常见的布式就是图片二维码,业内比较安全的验证是短信验证码,当然还有一些拼图验证码,码登加入人工智能的基于二维码等等,我们今天的现分主题就是前后端分离的图片二维码登录方案。高防服务器
未分离验证码登录方案
传统的布式项目大都是基于session交互的,前后端都在一个项目里面,验证比如传统的码登SSH项目或者一些JSP系统,当前端页面触发到获取验证码请求,基于可以将验证码里面的现分信息存在上下文中 ,所以登录的布式时候只需要 用户名、密码 、验证验证码即可 。源码下载码登
验证码生成流程如下
图片
登录验证流程如下
图片
可以发现,整个登录流程还是依赖session上下文的 ,并且由后端调整页面。
分离验证码登录方案
随着系统和业务的不停升级 ,前后端代码放在一起的项目越来越臃肿,已经无法快速迭代和职责区分了,于是纷纷投入了前后端分离的怀抱,发现代码和职责分离以后 ,模板下载开发效率越来越高了,功能迭代还越来越快,但是以前的验证码登录方案就要更改了 。
验证码生成流程如下
图片
对比原来的方案,增加了redis中间件 ,不再是存在session里面了 ,但是后面怎么区分这个验证码是这个请求生成的呢 ?所以我们加入了唯一标识符来区分
登录验证流程如下
图片
可以发现,亿华云基于前后端分离的分布式项目登录方案对比原来,加了一个redis中间件和token返回 ,不再依赖上下文session,并且页面调整也是由后端换到了前端
动手撸轮子
基于验证码的轮子还是挺多的,本文就以Kaptcha这个项目为例,通过springboot项目集成Kaptcha来实现验证码生成和登录方案。
Kaptcha介绍
Kaptcha是一个基于SimpleCaptcha的验证码开源项目
我找的云计算这个轮子是基于SimpleCaptcha二次封装的 ,maven依赖如下
复制<!--Kaptcha是一个基于SimpleCaptcha的验证码开源项目--> <dependency> <groupId>com.github.penggle</groupId> <artifactId>kaptcha</artifactId> <version>2.3.2</version> </dependency>1.2.3.4.5.6.新建项目并加入依赖
依赖主要有 SpringBoot 、Kaptcha、Redis
复制pom.xml <?xml versinotallow="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.lzp</groupId> <artifactId>kaptcha</artifactId> <version>1.0-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.0.RELEASE</version> <relativePath/><!-- lookup parent from repository --> </parent> <dependencies> <!--Kaptcha是一个基于SimpleCaptcha的验证码开源项目--> <dependency> <groupId>com.github.penggle</groupId> <artifactId>kaptcha</artifactId> <version>2.3.2</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- redis依赖commons-pool 这个依赖一定要添加 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.66.67. Redis配置类RedisConfig 复制@Configuration publicclass RedisConfig { @Bean public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory redisConnectionFactory){ RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>(); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer()); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer()); redisTemplate.setConnectionFactory(redisConnectionFactory); return redisTemplate; } }1.2.3.4.5.6.7.8.9.10.11.12.13.14.15. 验证码配置类KaptchaConfig 复制@Configuration publicclass KaptchaConfig { @Bean public DefaultKaptcha producer(){ DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); Properties properties = new Properties(); properties.setProperty("kaptcha.border", "no"); properties.setProperty("kaptcha.border.color", "105,179,90"); properties.setProperty("kaptcha.textproducer.font.color", "black"); properties.setProperty("kaptcha.image.width", "110"); properties.setProperty("kaptcha.image.height", "40"); properties.setProperty("kaptcha.textproducer.char.string","23456789abcdefghkmnpqrstuvwxyzABCDEFGHKMNPRSTUVWXYZ"); properties.setProperty("kaptcha.textproducer.font.size", "30"); properties.setProperty("kaptcha.textproducer.char.space","3"); properties.setProperty("kaptcha.session.key", "code"); properties.setProperty("kaptcha.textproducer.char.length", "4"); properties.setProperty("kaptcha.textproducer.font.names", "宋体,楷体,微软雅黑"); // properties.setProperty("kaptcha.obscurificator.impl","com.xxx");可以重写实现类 properties.setProperty("kaptcha.noise.impl","com.google.code.kaptcha.impl.NoNoise"); Config config = new Config(properties); defaultKaptcha.setConfig(config); return defaultKaptcha; }1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25. 验证码控制层CaptchaController为了方便代码写一块了,讲究看;
复制import com.google.code.kaptcha.impl.DefaultKaptcha; import com.lzp.kaptcha.service.CaptchaService; import com.lzp.kaptcha.vo.CaptchaVO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import sun.misc.BASE64Encoder; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.IOException; @RestController @RequestMapping("/captcha") publicclass CaptchaController { @Autowired private DefaultKaptcha producer; @Autowired private CaptchaService captchaService; @ResponseBody @GetMapping("/get") public CaptchaVO getCaptcha() throws IOException { // 生成文字验证码 String content = producer.createText(); // 生成图片验证码 ByteArrayOutputStream outputStream = null; BufferedImage image = producer.createImage(content); outputStream = new ByteArrayOutputStream(); ImageIO.write(image, "jpg", outputStream); // 对字节数组Base64编码 BASE64Encoder encoder = new BASE64Encoder(); String str = "data:image/jpeg;base64,"; String base64Img = str + encoder.encode(outputStream.toByteArray()).replace("\n", "").replace("\r", ""); CaptchaVO captchaVO =captchaService.cacheCaptcha(content); captchaVO.setBase64Img(base64Img); return captchaVO; } }1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50. 验证码返回对象CaptchaVO 复制public class CaptchaVO { /** * 验证码标识符 */ private String captchaKey; /** * 验证码过期时间 */ private Long expire; /** * base64字符串 */ private String base64Img; public String getCaptchaKey() { return captchaKey; } public void setCaptchaKey(String captchaKey) { this.captchaKey = captchaKey; } public Long getExpire() { return expire; } public void setExpire(Long expire) { this.expire = expire; } public String getBase64Img() { return base64Img; } public void setBase64Img(String base64Img) { this.base64Img = base64Img; } }1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38. 验证码方法层CaptchaService 复制import com.lzp.kaptcha.utils.RedisUtils; import com.lzp.kaptcha.vo.CaptchaVO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.util.UUID; @Service publicclass CaptchaService { @Value("${ server.session.timeout:300}") private Long timeout; @Autowired private RedisUtils redisUtils; privatefinal String CAPTCHA_KEY = "captcha:verification:"; public CaptchaVO cacheCaptcha(String captcha){ //生成一个随机标识符 String captchaKey = UUID.randomUUID().toString(); //缓存验证码并设置过期时间 redisUtils.set(CAPTCHA_KEY.concat(captchaKey),captcha,timeout); CaptchaVO captchaVO = new CaptchaVO(); captchaVO.setCaptchaKey(captchaKey); captchaVO.setExpire(timeout); return captchaVO; } }1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35. 用户登录对象封装LoginDTO 复制package com.lzp.kaptcha.dto; publicclass LoginDTO { private String userName; private String pwd; private String captchaKey; private String captcha; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } public String getCaptchaKey() { return captchaKey; } public void setCaptchaKey(String captchaKey) { this.captchaKey = captchaKey; } public String getCaptcha() { return captcha; } public void setCaptcha(String captcha) { this.captcha = captcha; } }1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44. 登录控制层UserController这块我写逻辑代码了 ,相信大家都看的懂;
复制import com.lzp.kaptcha.dto.LoginDTO; import com.lzp.kaptcha.utils.RedisUtils; import com.lzp.kaptcha.vo.UserVO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/user") publicclass UserController { @Autowired private RedisUtils redisUtils; @PostMapping("/login") public UserVO login(@RequestBody LoginDTO loginDTO) { Object captch = redisUtils.get(loginDTO.getCaptchaKey()); if(captch == null){ // throw 验证码已过期 } if(!loginDTO.getCaptcha().equals(captch)){ // throw 验证码错误 } // 查询用户信息 //判断用户是否存在 不存在抛出用户名密码错误 //判断密码是建站模板否正确 ,不正确抛出用户名密码错误 //构造返回到前端的用户对象并封装信息和生成token returnnew UserVO(); } }1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.验证码获取和查看
图片
图片
Tags:
转载:欢迎各位朋友分享到网络,但转载请说明文章出处“算法与编程”。http://www.bzli.cn/news/795e399201.html
相关文章
了解更多区块链技术在网络安全中的作用
IT资讯网络安全正在保护系统和网络免受数字攻击,这些攻击旨在访问、修改或破坏数字信息以勒索金钱或敏感数据。随着对技术和数据的日益依赖,加强安全措施以保护数字数据和交易至关重要。病毒、木马、Rootkit 等恶 ...
【IT资讯】
阅读更多windows10家庭版和专业版区别在哪
IT资讯我们都知道win10系统是有很多版本的,比如家庭版、旗舰版、专业版、教育版等等。那么不同的版本除了在基础功能上没有区别,它们在各自的功能性上还是有很大差别的。比如家庭版的功能就没有专业版的功能强大,因 ...
【IT资讯】
阅读更多如何用U盘装win10系统
IT资讯win10系统以其稳定性和良好的兼容性一直深受大家的喜爱,很多小伙伴但是不知道如何用U盘装win10系统,今天小编带来了下载的方式及其下载安装步骤,具体的解决方法下面一起来看看吧。用U盘装win10系 ...
【IT资讯】
阅读更多