Kaptcha验证码以及Cors 跨域的问题
Kaptcha验证码
搭建步骤
-
导入依赖
<!--验证码--> <dependency> <groupId>com.github.penggle</groupId> <artifactId>kaptcha</artifactId> <version>2.3.2</version> </dependency>
-
添加配置
创建一个配置类,并写如下内容
@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; } }
-
编写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); }
访问接口,生成验证码
因为我们是前后端分离的项目,通过前端地址:localhost:8080/login,调用后端接口localhost:8081/sys/user/captcha时,会报cors跨域的如下错误
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);
}
}
然后重启服务后访问,该问题就解决咯
特别还需要注意一个问题:后天返回的验证码图片通过输出流的方式返回,前端如何去接收显示图片?
方式一
如果只是返回验证码数据流到前端的话,可以使用如下方式
后台代码:
Vue前端:
解决方法
在页面加载的时候就会去向后端发送请求,需要注意的是在请求中添加 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;
})
}