zoukankan      html  css  js  c++  java
  • 图形验证码及其重构

    图形验证码

            <!--验证码组件-->
            <dependency>
                <groupId>com.github.penggle</groupId>
                <artifactId>kaptcha</artifactId>
                <version>2.3.2</version>
            </dependency>
    

    定义验证码

    public class ImageCode {
        private String code;
        //有效期
        private LocalDateTime expireTime;
        private BufferedImage image;
    
        public ImageCode(String code, int expireTime, BufferedImage image) {
            this.code = code;
            this.expireTime = LocalDateTime.now().plusSeconds(expireTime);
            this.image = image;
        }
    
        public String getCode() {
            return code;
        }
    
        public void setCode(String code) {
            this.code = code;
        }
    
        public LocalDateTime getExpireTime() {
            return expireTime;
        }
    
        public void setExpireTime(LocalDateTime expireTime) {
            this.expireTime = expireTime;
        }
    
        public BufferedImage getImage() {
            return image;
        }
    
        public void setImage(BufferedImage image) {
            this.image = image;
        }
    
        public boolean isExpried() {
            return LocalDateTime.now().isAfter(expireTime);
        }
    }
    
    

    请求的验证码会保存到session中

    @RestController
    public class ValidateCodeController {
        public static final String SESSION_KEY = "captcha";
    
        @Autowired
        private Producer captchaProducer;
        @Bean
        public Producer captcha(){
            Properties properties = new Properties();
            properties.setProperty("kaptcha.image.width","150");
            properties.setProperty("kaptcha.image.height","150");
            //字符集
            properties.setProperty("kaptcha.textproducer.char.string","0123456789");
            //字符长度
            properties.setProperty("kaptcha.textproducer.char.length","4");
            Config config = new Config(properties);
            DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
            defaultKaptcha.setConfig(config);
            return defaultKaptcha;
        }
    
        @GetMapping("/captcha")
        public void getCaptcha(HttpServletRequest request, HttpServletResponse response) throws IOException {
            response.setContentType("image/jpeg");
            String capText = captchaProducer.createText();
            BufferedImage bi = captchaProducer.createImage(capText);
            ImageCode imageCode = new ImageCode(capText,60,bi);
            request.getSession().setAttribute(SESSION_KEY,imageCode);
            ServletOutputStream out = response.getOutputStream();
            ImageIO.write(bi,"jpg",out);
            try {
                out.flush();
            } finally {
                out.close();
            }
        }
    }
    
    
    /**
     * 验证码异常
     */
    public class VerificationCodeException extends AuthenticationException {
        public VerificationCodeException(String msg) {
            super(msg);
        }
    }
    
    

    验证过滤器

    public class ValidateCodeFilter extends OncePerRequestFilter {
        public ValidateCodeFilter(AuthenticationFailureHandler flyAuthenticationFailureHandler) {
            this.flyAuthenticationFailureHandler = flyAuthenticationFailureHandler;
        }
    
        private AuthenticationFailureHandler flyAuthenticationFailureHandler;
    
        public AuthenticationFailureHandler getFlyAuthenticationFailureHandler() {
            return flyAuthenticationFailureHandler;
        }
    
        public void setFlyAuthenticationFailureHandler(AuthenticationFailureHandler flyAuthenticationFailureHandler) {
            this.flyAuthenticationFailureHandler = flyAuthenticationFailureHandler;
        }
    
        @Override
        protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
            if ("/authentication/form".equals(httpServletRequest.getRequestURI())
                &&"post".equalsIgnoreCase(httpServletRequest.getMethod())){
                try {
                    validate(httpServletRequest);
                }catch (VerificationCodeException e){
                    flyAuthenticationFailureHandler.onAuthenticationFailure(httpServletRequest,httpServletResponse,e);
                    return;
                }
            }
            filterChain.doFilter(httpServletRequest,httpServletResponse);
        }
    
        private void validate(HttpServletRequest request) {
            HttpSession session = request.getSession();
            ImageCode codeInSession = (ImageCode) session.getAttribute(ValidateCodeController.SESSION_KEY);
            String imageCode = request.getParameter("imageCode");
            if (StringUtils.isEmpty(imageCode)){
                throw new VerificationCodeException("验证码的值不能为空");
            }
            if (codeInSession==null){
                throw new VerificationCodeException("验证码不存在");
            }
            if (codeInSession.isExpried()){
                session.removeAttribute(ValidateCodeController.SESSION_KEY);
                throw new VerificationCodeException("验证码已过期");
            }
            if (!imageCode.equals(codeInSession.getCode())){
                throw new VerificationCodeException("验证码不匹配");
            }
            session.removeAttribute(ValidateCodeController.SESSION_KEY);
        }
    }
    
    

    将验证码过滤加到UsernamePasswordAuthenticationFilter前面,将图片验证码请求允许访问

      @Override
        protected void configure(HttpSecurity http) throws Exception {
            ValidateCodeFilter codeFilter = new ValidateCodeFilter(flyAuthenticationFailureHandler);
                http
                    .addFilterBefore(codeFilter, UsernamePasswordAuthenticationFilter.class)
                    .formLogin()
                    .loginPage("/authentication/request")
                    .loginProcessingUrl("/authentication/form")
                    .successHandler(flyAuthenticationSuccessHandler)
                    .failureHandler(flyAuthenticationFailureHandler)
                    .and()
                    .authorizeRequests()
                    .antMatchers("/authentication/request",
                            securityProperties.getBrowser().getLoginPage(),
                            "/captcha")
                    .permitAll()
                    .anyRequest().authenticated()
                    .and().csrf().disable();
        }
    

    开始login吧

    <form action="/authentication/form" method="post">
        用户名: <input type="text" name="username"><br>
        密码: <input type="password" name="password"><br>
        验证码:<input type="text" name="imageCode"><img src="/captcha">
        <input type="submit">
    </form>
    

    图形验证码重构

    public interface ValidateCodeGenerator {
        ImageCode generate(HttpServletRequest request);
    }
    
    public class ImageCodeGenerator implements ValidateCodeGenerator {
        @Autowired
        private SecurityProperties securityProperties;
        public void setSecurityProperties(SecurityProperties securityProperties) {
            this.securityProperties = securityProperties;
        }
    
        private Producer captcha(){
            Properties properties = new Properties();
            properties.setProperty("kaptcha.image.width",String.valueOf(securityProperties.getCode().getImageCode().getWidth()));
            properties.setProperty("kaptcha.image.height",String.valueOf(securityProperties.getCode().getImageCode().getHeight()));
            //字符集
            properties.setProperty("kaptcha.textproducer.char.string","0123456789");
            //字符长度
            properties.setProperty("kaptcha.textproducer.char.length",String.valueOf(securityProperties.getCode().getImageCode().getLength()));
            Config config = new Config(properties);
            DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
            defaultKaptcha.setConfig(config);
            return defaultKaptcha;
        }
        @Override
        public ImageCode generate(HttpServletRequest request) {
            Producer captchaProducer = captcha();
            String capText = captchaProducer.createText();
            BufferedImage bi = captchaProducer.createImage(capText);
            return new ImageCode(capText,securityProperties.getCode().getImageCode().getExpireIn(),bi);
        }
    }
    
    

    只需创建继承ValidateCodeGenerator的imageValidateCodeGenerator的bean就可以覆盖实现方法

    @Configuration
    public class ValidateCodeBeanConfig {
        @Autowired
        private SecurityProperties securityProperties;
    
        @Bean
        @ConditionalOnMissingBean(name = "imageValidateCodeGenerator")
        public ValidateCodeGenerator imageValidateCodeGenerator(){
            ImageCodeGenerator codeGenerator = new ImageCodeGenerator();
            codeGenerator.setSecurityProperties(securityProperties);
            return codeGenerator;
        }
    }
    
    
    @RestController
    public class ValidateCodeController {
        public static final String SESSION_KEY = "captcha";
    
        @Autowired
        private ValidateCodeGenerator imageCodeGenerator;
    
        @GetMapping("/captcha")
        public void getCaptcha(HttpServletRequest request, HttpServletResponse response) throws IOException {
            response.setContentType("image/jpeg");
            ImageCode imageCode = imageCodeGenerator.generate(request);
            request.getSession().setAttribute(SESSION_KEY,imageCode);
            ServletOutputStream out = response.getOutputStream();
            ImageIO.write(imageCode.getImage(),"jpg",out);
            try {
                out.flush();
            } finally {
                out.close();
            }
        }
    }
    

    用户自己实现

    @Component("imageValidateCodeGenerator")
    public class MyImageValidateCodeGenerator implements ValidateCodeGenerator {
        public ImageCode generate(HttpServletRequest request) {
            System.out.println("图形验证码实现");
            //。。。
            return null;
        }
    }
    
  • 相关阅读:
    708. Insert into a Cyclic Sorted List
    24. Swap Nodes in Pairs
    877. Stone Game
    EOJ Monthly 2020.7 A. 打字机(前缀和+思维)
    EOJ Monthly 2020.7 B. 线上考试(排列组合)
    【JavaScript】Generator
    【JavaScript】Promise
    【JavaScript】throw 和 try...catch
    【JavaScript】JSON
    【JavaScript】WeakSet
  • 原文地址:https://www.cnblogs.com/fly-book/p/12239970.html
Copyright © 2011-2022 走看看