This article outline
[TOC]
preface
In order to prevent the destruction of the world, in order to protect the peace of the world… If you say wrong, try again
In order to prevent the authentication system have been violent attacks, many systems have increased captcha efficacy, common picture is qr code, the industry safer is a message authentication code, and of course some puzzles captcha, join the qr code of artificial intelligence and so on, today our topic is the separation of front and back side pictures qr code login.
Login scheme with unseparated verification codes at the front and back ends
Traditional projects are based on session interaction, and both the front and back end are in a project, such as traditional SSH projects or some JSP systems. When the front end page triggers the request to obtain the verification code, the information in the verification code can be stored in the context, so only the user name, password and verification code are needed for login.
The verification code generation process is as follows
The login verification process is as follows
As you can see, the entire login process is still dependent on the Session context and the backend adjusts the page.
Verification code login scheme separated from the front and back ends
With constantly upgrade system and business, client-side code together before and after the project is more and more bloated, already can’t rapid iteration, and responsibility to distinguish, rushed into the arms of the front and back end separation, found that code and after separation of duties, development efficiency is higher and higher, the functional iteration is faster and faster, but previous login authentication code scheme is about to change.
The verification code generation process is as follows
Compared with the original scheme, the redis middleware is added, which is no longer stored in the session. However, how to distinguish the verification code generated by this request? So we added a unique identifier to distinguish them
The login verification process is as follows
It can be found that compared with the original distributed project login scheme based on the separation of the front and back ends, a Redis middleware and token return are added, and the context session is no longer dependent, and page adjustment is also changed from the back end to the front end
Hand off the wheel
There are a lot of wheels based on verification code. This paper takes Kaptcha as an example to integrate Kaptcha through Springboot project to achieve verification code generation and login scheme.
Introduce Kaptcha
Kaptcha is an open source captcha project based on SimpleCaptcha
The wheel I’m looking for is based on SimpleCaptcha secondary encapsulation, and Maven relies on the following
<! > <dependency> <groupId>com.github. Penggle </groupId> < artifactId > kaptcha < / artifactId > < version > 2.3.2 < / version > < / dependency >Copy the code
Create a new project and add dependencies
The main dependencies are 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 - the SNAPSHOT < / version > < the parent > < groupId > org. Springframework. Boot < / groupId > The < artifactId > spring - the boot - starter - parent < / artifactId > < version > 2.3.0. RELEASE < / version > < relativePath / > <! -- lookup parent from repository --> </parent> <dependencies> <! > <dependency> <groupId>com.github. Penggle </groupId> < artifactId > kaptcha < / artifactId > < version > 2.3.2 < / version > < / dependency > < the 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> <! Mons </groupId> </groupId> <artifactId>commons-pool2</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> < artifactId > fastjson < / artifactId > < version > 1.2.3 < / version > < / dependency > < the 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>Copy the code
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);
returnredisTemplate; }}Copy the code
Verification code configuration classKaptchaConfig
@Configuration
public class KaptchaConfig {
@Bean
public DefaultKaptcha producer(a){
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
Properties properties = new Properties();
properties.setProperty("kaptcha.border"."no");
properties.setProperty("kaptcha.border.color"."105179, living");
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, Regular script, 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;
}
Copy the code
Captcha control layerCaptchaController
In order to facilitate the code to write a piece, pay attention to look
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(a) throws IOException {
// Generate a literal captcha
String content = producer.createText();
// Generate image captcha
ByteArrayOutputStream outputStream = null;
BufferedImage image = producer.createImage(content);
outputStream = new ByteArrayOutputStream();
ImageIO.write(image, "jpg", outputStream);
// Base64 encodes byte arrays
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);
returncaptchaVO; }}Copy the code
Verification code returns an objectCaptchaVO
package com.lzp.kaptcha.vo;
public class CaptchaVO {
/** * Verification code identifier */
private String captchaKey;
/** * Verification code expiration time */
private Long expire;
/** * base64 The character string */
private String base64Img;
public String getCaptchaKey(a) {
return captchaKey;
}
public void setCaptchaKey(String captchaKey) {
this.captchaKey = captchaKey;
}
public Long getExpire(a) {
return expire;
}
public void setExpire(Long expire) {
this.expire = expire;
}
public String getBase64Img(a) {
return base64Img;
}
public void setBase64Img(String base64Img) {
this.base64Img = base64Img; }}Copy the code
Redis wrapper classRedisUtils
Online random find, class inside indicate the source, will use, more code is not posted, the end of the code to obtain
Captcha method layerCaptchaService
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);
returncaptchaVO; }}Copy the code
User login object encapsulationLoginDTO
package com.lzp.kaptcha.dto;
public class LoginDTO {
private String userName;
private String pwd;
private String captchaKey;
private String captcha;
public String getUserName(a) {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPwd(a) {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public String getCaptchaKey(a) {
return captchaKey;
}
public void setCaptchaKey(String captchaKey) {
this.captchaKey = captchaKey;
}
public String getCaptcha(a) {
return captcha;
}
public void setCaptcha(String captcha) {
this.captcha = captcha; }}Copy the code
Login control layerUserController
I wrote the logical code, I believe you all understand
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 the verification code has expired
}
if(! loginDTO.getCaptcha().equals(captch)){// throw verification code error
}
// Query user information
// Check whether the user does not throw a username or password error
// Check whether the password is correct. If not, throw the username and password error
// Construct the user object returned to the front end and encapsulate the information and generate tokens
return newUserVO(); }}Copy the code
Obtain and view the verification code
The code for
Code has been uploaded to the address library, remember to add a star mark oh!
Github.com/pengziliu/G…
Check back for more highlights