[Spring Security OAuth2 Notebook Series] - spring security - Picture Verification Code Reconstruction

Keywords: Spring Attribute JSON Java

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

Posted by warriors2003 on Mon, 24 Dec 2018 15:06:06 -0800