Kaptcha验证码以及Cors 跨域的问题

Kaptcha验证码

搭建步骤

  1. 导入依赖

    <!--验证码-->
    <dependency>
        <groupId>com.github.penggle</groupId>
        <artifactId>kaptcha</artifactId>
        <version>2.3.2</version>
    </dependency>
    
  2. 添加配置

    创建一个配置类,并写如下内容

    @Configuration
    public class KaptchaConfig {
    
        @Bean
        public DefaultKaptcha producer()
        {
            
            Properties properties = new Properties();
            properties.put("kaptcha.border", "no");
            properties.put("kaptcha.textproducer.font.color", "black");
            properties.put("kaptcha.textproducer.char.space", "5");
            Config config = new Config(properties);
            DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
            defaultKaptcha.setConfig(config);
            
           /* Properties properties = new Properties();
            //图片边框,合法值yes,no,默认值yes
            properties.put("kaptcha.border","no");
            //边框颜色,合法值rgb(and optional alpha)或者 white,black,blue,默认值black
            properties.put("kaptcha.border.color","blue");
            //边框厚度,合法值>0,默认值为1
            properties.put("kaptcha.border.thickness",2);
            //图片宽度,默认值200
            properties.put("kaptcha.image.width",120);
            //图片高度,默认值50
            properties.put("kaptcha.image.height",40);
            //图片实现类,默认值priv.kerlomz.kaptcha.impl.DefaultKaptcha
            properties.put("kaptcha.producer.impl","priv.kerlomz.kaptcha.impl.DefaultKaptcha");
            //文本实现类,默认值priv.kerlomz.kaptcha.impl.DefaultTextCreator
            properties.put("kaptcha.textproducer.impl","priv.kerlomz.kaptcha.text.impl.DefaultTextCreator");
            //文本集合,验证码值从此集合中获取,默认值abcde2345678gfynmnpwx
            properties.put("kaptcha.textproducer.char.string","abcde2345678gfynmnpwx");
            //验证码长度,默认值为5
            properties.put("kaptcha.textproducer.char.length","5");
            //字体,默认值Arial, Courier(如果使用中文验证码,则必须使用中文的字体,否则出现乱码)
            properties.put("kaptcha.textproducer.font.names","Arial");
            //字体大小,默认值为40px;
            properties.put("kaptcha.textproducer.font.size","40");
            //字体颜色,合法值: r,g,b 或者 white,black,blue,默认值black
            properties.put("kaptcha.textproducer.font.color","black");
            //文字间隔,默认值为2
            properties.put("kaptcha.textproducer.char.space","2");
            //干扰实现类,默认值priv.kerlomz.kaptcha.impl.DefaultNoise
            properties.put("kaptcha.noise.impl","priv.kerlomz.kaptcha.impl.DefaultNoise");
            //干扰 颜色,合法值: r,g,b 或者 white,black,blue,默认值black
            properties.put("kaptcha.noise.color","black");
            *//**图片样式:
             水纹 priv.kerlomz.kaptcha.impl.WaterRipple
             鱼眼 priv.kerlomz.kaptcha.impl.FishEyeGimpy
             阴影 priv.kerlomz.kaptcha.impl.ShadowGimpy, 默认值水纹
             **//*
            properties.put("kaptcha.obscurificator.impl","priv.kerlomz.kaptcha.impl.WaterRipple");
            //背景实现类,默认值priv.kerlomz.kaptcha.impl.DefaultBackground
            properties.put("kaptcha.background.impl","priv.kerlomz.kaptcha.impl.DefaultBackground");
            //背景颜色渐变,开始颜色,默认值lightGray/192,193,193
            properties.put("kaptcha.background.clear.from","255,255,255");
            //背景颜色渐变, 结束颜色,默认值white
            properties.put("kaptcha.background.clear.to","white");
            //文字渲染器,默认值priv.kerlomz.kaptcha.text.impl.DefaultWordRenderer
            properties.put("kaptcha.word.impl","priv.kerlomz.kaptcha.text.impl.DefaultWordRenderer");
    
            Config config = new Config(properties);
            DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
            defaultKaptcha.setConfig(config);
            return defaultKaptcha;*/
            return defaultKaptcha;
        }
    }
    
    
  3. 编写controller,生成验证码图片

        /**
         * 生成验证码
         * @return
         */
        @GetMapping("/captcha")
        public void captcha(HttpServletResponse response) throws IOException {
            response.setHeader("Cache-Control", "no-store, no-cache");
            response.setContentType("image/jpeg");
    
            String code = producer.createText();
            String key = UUID.randomUUID().toString();
    
            BufferedImage image = producer.createImage(code);
    
            ServletOutputStream outputStream = response.getOutputStream();
            ImageIO.write(image,"jpg",outputStream);
    
        }
    

    访问接口,生成验证码

    image-20210713130507686

因为我们是前后端分离的项目,通过前端地址:localhost:8080/login,调用后端接口localhost:8081/sys/user/captcha时,会报cors跨域的如下错误

image-20210713133321844

Cors跨域问题

1.什么是Cors跨域

CORS是一个w3c标准,全称是"跨域资源共享"(Cross-origin resource sharing),但一个请求url的协议,域名,端口三者之间任意与当前页面地址不同即为跨域.它允许阅览器向跨源服务器发送XMLHttpRequest请求,从而客服AJAX只能同源使用的限制.
参考:https://www.cnblogs.com/lishanlei/p/8823823.html

2.解决方法

在后端代码中新添加一个corsConfig的配置类,添加如下代码

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

/**
 * @author : sean
 * @version V1.0
 * @Project: vueadmin
 * @Package com.sean.vueadmin.config
 * @date Date : 2021年07月13日 13:29
 * @Description: Springboot解决cors跨域问题
 */
@Configuration
public class CorsConfig {


    private CorsConfiguration buildConfig() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        return corsConfiguration;
    }

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", buildConfig());
        return new CorsFilter(source);
    }

}

然后重启服务后访问,该问题就解决咯

image-20210713140844545

特别还需要注意一个问题:后天返回的验证码图片通过输出流的方式返回,前端如何去接收显示图片?

方式一

如果只是返回验证码数据流到前端的话,可以使用如下方式

后台代码:

image-20210713141143794

Vue前端:

image-20210713141247655

解决方法

在页面加载的时候就会去向后端发送请求,需要注意的是在请求中添加 responseType:’blob’

 //获取验证码
getCaptcha(){
    this.$axios.get('/sys/user/captcha',{ responseType: 'blob'}).then(res =>{

        this.captchaImg = window.URL.createObjectURL(res.data);

        /* this.captchaImg = res.data.data.captchaImg;
                    this.loginForm.token = res.data.data.token;*/
    })
}

方式二

如果除了返回验证码图片外还需要返回其它的数据,就不能直接将图片流返回。比如将生成的验证码code保存到redis中,进行登录的时候需要和前端传过来的验证码做检验,此时首先需要从redis中取出保存的验证码的code,因此我们还需要向前端返回一个redis的key回去才能从redis中取出保存的值.

后台代码controller:

@GetMapping("/captcha")
public ResponseResult captcha(HttpServletResponse response) throws IOException {
    //方法二:返回生成的二维码和保存在redis中的key返回给前端

    String code = producer.createText();
    String key = UUID.randomUUID().toString();

    //将生成的验证码保存到redis中,并且过期时间为5分钟
    redisUtil.hset(Const.CAPTCHA_KEY,key,code,60*5);

    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    ImageIO.write(producer.createImage(code),"jpg",outputStream);

    BASE64Encoder base64Encoder = new BASE64Encoder();
    String base64Img = "data:image/jpeg;base64," + base64Encoder.encode(outputStream.toByteArray());

    return ResponseResult.createBySuccess(MapUtil.builder().put("captchaImg",base64Img).put("token",key).build());
}

前端vue代码

 //获取验证码
getCaptcha(){
    this.$axios.get('/sys/user/captcha').then(res =>{
        /*
                  //方法1:直接生成图片返回
                  this.captchaImg = window.URL.createObjectURL(res.data);*/

        //方法2:将生成的图片转换成Base64
        this.captchaImg = res.data.data.captchaImg;
        this.loginForm.token = res.data.data.token;
    })
}
posted @ 2021-07-13 14:18  肖恩雷  阅读(659)  评论(0编辑  收藏  举报