Picture Verification Code Reconstruction
- Basic parameters of verification codes are configurable
- Configurable Interface for Verification Code Check Interception
- The generation logic of verification codes is configurable
Configuration of Basic Validation Code Parameters
Level 3 coverage: The top will cover the configuration of the lower level
_Request-level configuration: Configuration values are passed when the interface is invoked _Application-level configuration: Configuration is written in the security-demo project Default Configuration: Configuration values are written in the security-core project
Graphic Verification Code Configuration Class
package cn.mrcode.imooc.springsecurity.securitycore.properties;
/**
* Graphic Verification Code
* @author zhuqiang
* @version 1.0.1 2018/8/4 10:03
* @date 2018/8/4 10:03
* @since 1.0
*/
public class ImageCodeProperties {
private int width = 67;
private int height = 23;
private int length = 4; // Verification code length
private int expireIn = 60; // Expiration date
Verification Code Configuration Class
package cn.mrcode.imooc.springsecurity.securitycore.properties;
/**
* Configuration for encapsulating validation codes
* @author zhuqiang
* @version 1.0.1 2018/8/4 10:06
* @date 2018/8/4 10:06
* @since 1.0
*/
public class ValidateCodeProperties {
private ImageCodeProperties image = new ImageCodeProperties();
// The configuration of SMS verification code will be added later.
Added to the General Configuration Class
@ConfigurationProperties(prefix = "imooc.security")
public class SecurityProperties {
/** imooc.security.browser The configuration under the path is mapped to the configuration class */
private BrowserProperties browser = new BrowserProperties();
private ValidateCodeProperties code = new ValidateCodeProperties();
Modification Processing Logic Office
cn.mrcode.imooc.springsecurity.securitycore.validate.code.ValidateCodeController
private ImageCode createImageCode(HttpServletRequest request) throws IOException {
ImageCodeProperties imageProperties = securityProperties.getCode().getImage();
// Get it from the request and then from the configuration
// If the configuration is not overwritten, it is the default configuration.
int width = ServletRequestUtils.getIntParameter(request, "width", imageProperties.getWidth());
int height = ServletRequestUtils.getIntParameter(request, "height", imageProperties.getHeight());
int length = ServletRequestUtils.getIntParameter(request, "length", imageProperties.getLength());
int expireIn = ServletRequestUtils.getIntParameter(request, "expireIn", imageProperties.getExpireIn());
String code = RandomStringUtils.randomNumeric(length);
BufferedImage image = createImageCode(width, height, code);
return new ImageCode(image, code, expireIn);
}
Configurable Interface for Verification Code Check Interception
Ideas for realization:
1. Provide url interception address configuration properties
2. Get the configuration attributes in the filter and match them iteratively
Add url configuration properties
public class ImageCodeProperties {
private int width = 67;
private int height = 23;
private int length = 4; // Verification code length
private int expireIn = 60; // Expiration date
private String url; // Comma-separated interface url path to verify
Matching logic for target url in filters
public class ValidateCodeFilter extends OncePerRequestFilter implements InitializingBean {
// Injection where this class is initialized
// Generally, you add filters where you configure security http
private AuthenticationFailureHandler failureHandler;
private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();
// Pass in from the initialization place
private SecurityProperties securityProperties;
// Store all URLs that need to be intercepted
private Set<String> urls;
private AntPathMatcher pathMatcher = new AntPathMatcher();
/**
* org.springframework.beans.factory.InitializingBean Ensure that after all other properties are set, there are bean Factory calls
* But there is still a need to call this method at the initialization point.
* @throws ServletException
*/
@Override
public void afterPropertiesSet() throws ServletException {
super.afterPropertiesSet();
String url = securityProperties.getCode().getImage().getUrl();
String[] configUrl = StringUtils.split(url, ",");
urls = Stream.of(configUrl).collect(Collectors.toSet());
urls.add("/authentication/form"); // Login request
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
// For login requests, and for post requests
boolean action = false;
for (String url : urls) {
// Org. spring framework. util. AntPathMatcher can match the url pattern in spring
// The kind that supports wildcard paths
if (pathMatcher.match(url, request.getRequestURI())) {
action = true;
}
}
if (action) {
try {
validate(request);
} catch (ValidateCodeException e) {
failureHandler.onAuthenticationFailure(request, response, e);
return;
}
}
filterChain.doFilter(request, response);
}
Attribute injection in the original configuration center
cn.mrcode.imooc.springsecurity.securitybrowser.BrowserSecurityConfig
// There are three configure methods, which use the http parameter
@Override
protected void configure(HttpSecurity http) throws Exception {
// The easiest way to modify the default configuration
// In v5 +, this configuration (form login) should be the default configuration
// basic login (i.e. bullet-box login) should be the default version of v5-
ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter();
validateCodeFilter.setFailureHandler(myAuthenticationFailureHandler);
validateCodeFilter.setSecurityProperties(securityProperties); // Injection configuration attribute class
validateCodeFilter.afterPropertiesSet(); // Initialize url configuration
Test: security-demo/application.yml
imooc:
security:
browser:
# loginPage: /demo-signIn.html
# loginType: REDIRECT
loginType: JSON
code:
image:
width: 100
height: 50
url: /order,/user/* # Verification code interception */ for orders and all user paths
The generation logic of verification codes is configurable
Idea: Logical compatibility, which is abstracted into interfaces and then provided by the client
The idea here is very powerful, let me learn how to achieve the default configuration in spring.
Provide an interface for generating picture information
package cn.mrcode.imooc.springsecurity.securitycore.validate.code;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
public interface ValidateCodeGenerate {
ImageCode generate(HttpServletRequest request) throws IOException;
}
Implementing default image generation interface class
cn.mrcode.imooc.springsecurity.securitycore.validate.code.ImageCodeGenerate
public class ImageCodeGenerate implements ValidateCodeGenerate {
private ImageCodeProperties imageProperties;
public ImageCodeGenerate(ImageCodeProperties imageProperties) {
this.imageProperties = imageProperties;
}
@Override
public ImageCode generate(HttpServletRequest request) throws IOException {
return createImageCode(request);
}
public ImageCode createImageCode(HttpServletRequest request) throws IOException {
int width = ServletRequestUtils.getIntParameter(request, "width", imageProperties.getWidth());
int height = ServletRequestUtils.getIntParameter(request, "height", imageProperties.getHeight());
int length = ServletRequestUtils.getIntParameter(request, "length", imageProperties.getLength());
int expireIn = ServletRequestUtils.getIntParameter(request, "expireIn", imageProperties.getExpireIn());
String code = RandomStringUtils.randomNumeric(length);
BufferedImage image = createImageCode(width, height, code);
return new ImageCode(image, code, expireIn);
}
...What follows is that the specific tool class code is not pasted.
Increase the configuration class and initialize the image generator instance; this is the key!!
package cn.mrcode.imooc.springsecurity.securitycore.validate.code;
import cn.mrcode.imooc.springsecurity.securitycore.properties.SecurityProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ValidateCodeConfig {
@Autowired
private SecurityProperties securityProperties;
@Bean
// If there is an imageCodeGenerate bean in the spring container, it will not be initialized again.
// Conditional annotation
@ConditionalOnMissingBean(name = "imageCodeGenerate")
public ValidateCodeGenerate imageCodeGenerate() {
ImageCodeGenerate imageCodeGenerate = new ImageCodeGenerate(securityProperties.getCode().getImage());
return imageCodeGenerate;
}
}
Previous calls were modified to call interfaces
public class ValidateCodeController {
public static final String SESSION_KEY = "SESSION_KEY_IMAGE_CODE";
private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();
@Autowired
private SecurityProperties securityProperties;
@Autowired // Processing Information Using Generated Interfaces
private ValidateCodeGenerate validateCodeGenerate;
Finally, test ideas:
1. Ensure that the reconstructed code works properly
2. In the demo project, the implementer initializes a ValidateCodeGenerate implementation class and debugs it to see if it comes into our own generation logic.
Summary
Knowledge Points in this Chapter
* SessionStrategy
* @Conditional OnMissing Bean (name = imageCodeGenerate) bean condition annotation
* AntPathMatcher Path Tool Class