Explain the implementation of login authentication code function with open source software kaptcha

1. Configuration of Authentication Code Generation uses kaptcha

Implement class library kaptcha using google open source validation code, introduced by maven coordinates

<dependency>
   <groupId>com.github.penggle</groupId>
   <artifactId>kaptcha</artifactId>
   <version>2.3.2</version>
   <exclusions>
      <exclusion>
         <artifactId>javax.servlet-api</artifactId>
         <groupId>javax.servlet</groupId>
      </exclusion>
   </exclusions>
</dependency>
  • Assuming our configuration file is application.yml, create a new single file called kaptcha.properties.Because kaptcha is not configured in the standard format of yaml, only properties can be used.Use with annotation PropertySourc e.
  • Assuming our configuration file is application.properties, you can add this code instead of creating a separate file.
  • The validation code configurations below are easy to understand from the perspective of English words and can be modified when we need to adjust the properties of the validation code, such as border, color, size, font, etc.
kaptcha.border=no
kaptcha.border.color=105,179,90
kaptcha.image.width=100
kaptcha.image.height=45
kaptcha.session.key=code
kaptcha.textproducer.font.color=blue
kaptcha.textproducer.font.size=35
kaptcha.textproducer.char.length=4
kaptcha.textproducer.font.names=Song Style,Kai Typography,Microsoft YaHei

The following code loads the kaptcha configuration in the configuration file (refer to the configuration load for Spring Boot) and, if it is a stand-alone property file, the PropertySource annotation is required.
In addition, we initialize the Spring Bean of captchaProducer by loading the completed configuration to generate the verification code.

@Component
@PropertySource(value = {"classpath:kaptcha.properties"})
public class CaptchaConfig {

    @Value("${kaptcha.border}")
    private String border;
    @Value("${kaptcha.border.color}")
    private String borderColor;
    @Value("${kaptcha.textproducer.font.color}")
    private String fontColor;
    @Value("${kaptcha.image.width}")
    private String imageWidth;
    @Value("${kaptcha.image.height}")
    private String imageHeight;
    @Value("${kaptcha.session.key}")
    private String sessionKey;
    @Value("${kaptcha.textproducer.char.length}")
    private String charLength;
    @Value("${kaptcha.textproducer.font.names}")
    private String fontNames;
    @Value("${kaptcha.textproducer.font.size}")
    private String fontSize;

    @Bean(name = "captchaProducer")
    public DefaultKaptcha getKaptchaBean() {
        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
        Properties properties = new Properties();
        properties.setProperty("kaptcha.border", border);
        properties.setProperty("kaptcha.border.color", borderColor);
        properties.setProperty("kaptcha.textproducer.font.color", fontColor);
        properties.setProperty("kaptcha.image.width", imageWidth);
        properties.setProperty("kaptcha.image.height", imageHeight);
        properties.setProperty("kaptcha.session.key", sessionKey);
        properties.setProperty("kaptcha.textproducer.char.length", charLength);
        properties.setProperty("kaptcha.textproducer.font.names", fontNames);
        properties.setProperty("kaptcha.textproducer.font.size",fontSize);
        Config config = new Config(properties);
        defaultKaptcha.setConfig(config);
        return defaultKaptcha;
    }

}

We have now finished configuring the Kaptcha Open Source Authentication Code software. If you find that the configuration file in IDEA reads Chinese random code, modify the following configuration.

2. session Save of Authentication Code Generation

Controller that generates the verification code.It also requires access to the open path'/kaptcha', which is configured to be accessible without login and without any privileges.How to configure, I have already talked about in the previous article.

  • Authentication code text is generated from captchaProducer.createText() and saved in CaptchaImageVO with the expiration time.
  • Save the CaptchaImageVO Authentication Code information class object to session.(This class is described later in the code)
  • Generate a captchaProducer.createImage(capText) picture of the verification code and return it to the front end via ServletOutputStream
@RestController
public class CaptchaController {

    @Resource
    DefaultKaptcha captchaProducer;

    /**
     * Get Authentication Code
     */
    @RequestMapping(value = "/kaptcha", method = RequestMethod.GET)
    public void kaptcha(HttpSession session, HttpServletResponse response) throws Exception {

        response.setDateHeader("Expires", 0);
        response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
        response.addHeader("Cache-Control", "post-check=0, pre-check=0");
        response.setHeader("Pragma", "no-cache");
        response.setContentType("image/jpeg");

        String capText = captchaProducer.createText();
        CaptchaImageVO captchaImageVO = new CaptchaImageVO(capText,2 * 60);
        //Save Authentication Code to session
        session.setAttribute(Constants.KAPTCHA_SESSION_KEY, captchaImageVO);

        //Return Pictures to Front End
        try(ServletOutputStream out = response.getOutputStream();) {
            BufferedImage bi = captchaProducer.createImage(capText);
            ImageIO.write(bi, "jpg", out);
            out.flush();
        }//Use try-with-resources without closing the stream manually
    }

}

We're going to save CaptchaImageVO into session.Therefore, do not add pictures in this class, just save the verification code text and expiration time for subsequent verification.Saving the captcha pictures is useless and a waste of memory.

@Data
public class CaptchaImageVO {

    //Verification Code Text
    private String code;
    //Verification code expiration time
    private LocalDateTime expireTime;
 
    public CaptchaImageVO(String code, int expireAfterSeconds){
        this.code = code;
        this.expireTime = LocalDateTime.now().plusSeconds(expireAfterSeconds);
    }
 
    //Whether the verification code is invalid
    public boolean isExpried() {
        return LocalDateTime.now().isAfter(expireTime);
    }
 
}

3. Authentication Code User Access

Add the following code to the appropriate location on the login page, and note that the picture img tag is placed in the login form.

<img src="/kaptcha" id="kaptcha" width="110px" height="40px"/>

<script>
    window.onload=function(){
        var kaptchaImg = document.getElementById("kaptcha");
        kaptchaImg.onclick = function(){
            kaptchaImg.src = "/kaptcha?" + Math.floor(Math.random() * 100)
        }
    }
</script>
  • The effect is that the verification code is loaded when the page is initialized.Each subsequent click updates the verification code.
  • Note: Make sure to set the width and height, otherwise the picture cannot be displayed.

4. Safety Verification of Authentication Codes

  • Write our custom Picture Authentication CodeFilter, which intercepts login requests
  • VerificationCodeFilter filter Get Authentication Code Text from Seeion to compare with user input, compare by executing other filter chains
  • Customize an exception for AuthenticationFailureHandler to handle if the comparison fails
  • Finally, place the Verification CodeFilter before the UsernamePasswordAuthenticationFilter form filter.

The above is the logic to implement login authentication code validation in Spring Security.It's easier if you're using shiro or other custom implementation of login authentication.Just pull out the session comparison validation code from your login validation controller without the need for a custom filter.

Looking forward to your attention

Tags: Java Session Spring Google Maven

Posted on Thu, 28 Nov 2019 21:44:36 -0800 by Adrianphp