Foreword
In order to prevent the verification system from being violently cracked, many systems have added verification code verification. The more common one is the picture QR code. The safer one in the industry is the SMS verification code. Of course, there are also some puzzle verification codes and QR codes with artificial intelligence. Wait, our topic today is a picture QR code login solution that separates the front and back ends.
Verification code login solution without separation of front and back ends
Most traditional projects are based on session interaction, and the front-end and back-end are both in one project, such as traditional SSH projects or some JSP systems. When the current-end page triggers a request to obtain a verification code, the information in the verification code can be stored in the context, so When logging in, you only need a username, password, and verification code.
The verification code generation process is as follows
The login verification process is as follows
It can be found that the entire login process still relies on the session context, and the page is adjusted by the backend.
Verification code login solution with separate front-end and back-end
With the continuous upgrading of systems and businesses, projects with front-end and back-end code put together are becoming more and more bloated, and it is no longer possible to quickly iterate and separate responsibilities. Therefore, many people have embraced the separation of front-end and back-end. They found that after the separation of code and responsibilities, development The efficiency is getting higher and higher, and the function iteration is getting faster and faster, but the previous verification code login scheme will be changed.
The verification code generation process is as follows
Compared with the original solution, the redis middleware is added, which is no longer stored in the session, but how to distinguish whether the verification code is generated by this request? So we added a unique identifier to distinguish
The login verification process is as follows
It can be found that compared with the original distributed project login solution based on front-end and back-end separation, a redis middleware and token return are added, which no longer relies on the context session, and the page adjustment is also changed from the back-end to the front-end.
Roll the wheel
There are still many wheels based on verification codes. This article takes the Kaptcha project as an example and integrates Kaptcha through the springboot project to implement verification code generation and login solutions.
Introduction to Kaptcha
Kaptcha is a verification code open source project based on SimpleCaptcha
The wheel I am looking for is based on SimpleCaptcha secondary encapsulation. The maven dependencies are as follows
<!--Kaptcha is a verification code open source project based on SimpleCaptcha--> <dependency> <groupId>com.github.penggle</groupId> <artifactId>kaptcha</artifactId> <version>2.3.2</version> </dependency>
Create a new project and add dependencies
Dependencies mainly include SpringBoot, Kaptcha, and Redis
pom.xml <?xml version="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 is an open source verification code project based on 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 depends on commons-pool. This dependency must be added --> <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>
Redis configuration classRedisConfig
@Configuration public class 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; } }
Verification code configuration class KaptchaConfig
@Configuration public class 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", "Song style, Kai style, Microsoft Yahei"); // properties.setProperty("kaptcha.obscurificator.impl","com.xxx"); You can override the implementation class properties.setProperty("kaptcha.noise.impl","com.google.code.kaptcha.impl.NoNoise"); Config config = new Config(properties); defaultKaptcha.setConfig(config); return defaultKaptcha; }
Verification code control layer CaptchaController
For the convenience of writing the code, I pay attention to reading
package com.lzp.kaptcha.controller; 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") public class CaptchaController {<!-- --> @Autowired private DefaultKaptcha producer; @Autowired private CaptchaService captchaService; @ResponseBody @GetMapping("/get") public CaptchaVO getCaptcha() throws IOException {<!-- --> // Generate text verification code String content = producer.createText(); // Generate image verification code ByteArrayOutputStream outputStream = null; BufferedImage image = producer.createImage(content); outputStream = new ByteArrayOutputStream(); ImageIO.write(image, "jpg", outputStream); // Base64 encode the byte array BASE64Encoder encoder = new BASE64Encoder(); String str = "data:image/jpeg;base64,"; String base64Img = str + encoder.encode(outputStream.toByteArray()).replace("\\ ", "").replace("\r", ""); CaptchaVO captchaVO =captchaService.cacheCaptcha(content); captchaVO.setBase64Img(base64Img); return captchaVO; } }
Verification code returns object CaptchaVO
package com.lzp.kaptcha.vo; public class CaptchaVO {<!-- --> /** * Verification code identifier */ private String captchaKey; /** * Verification code expiration time */ private Long expire; /** * base64 string */ 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; } }
Redis encapsulation class RedisUtils
I can find it randomly on the Internet, indicate the source in the category, and just use it. If there are too many codes, I won’t post them.
Verification code method layer CaptchaService
package com.lzp.kaptcha.service; 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 public class CaptchaService {<!-- --> @Value("${server.session.timeout:300}") private Long timeout; @Autowired private RedisUtils redisUtils; private final String CAPTCHA_KEY = "captcha:verification:"; public CaptchaVO cacheCaptcha(String captcha){<!-- --> //Generate a random identifier String captchaKey = UUID.randomUUID().toString(); //Cache the verification code and set the expiration time redisUtils.set(CAPTCHA_KEY.concat(captchaKey),captcha,timeout); CaptchaVO captchaVO = new CaptchaVO(); captchaVO.setCaptchaKey(captchaKey); captchaVO.setExpire(timeout); return captchaVO; } }
User login object encapsulates LoginDTO
package com.lzp.kaptcha.dto; public class 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; } }
Login control layer UserControlle
I have written the logic code for this, I believe everyone can understand it.
package com.lzp.kaptcha.controller; 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") public class UserController {<!-- --> @Autowired private RedisUtils redisUtils; @PostMapping("/login") public UserVO login(@RequestBody LoginDTO loginDTO) {<!-- --> Object captch = redisUtils.get(loginDTO.getCaptchaKey()); if(captch == null){<!-- --> // throw verification code has expired } if(!loginDTO.getCaptcha().equals(captch)){<!-- --> // throw verification code error } // Query user information //Determine whether the user exists. If it does not exist, a username and password error will be thrown. //Determine whether the password is correct. If it is incorrect, an incorrect username and password will be thrown. //Construct the user object returned to the front end and encapsulate the information and generate token return new UserVO(); } }
Get and view verification code