文章目录
一、验证码的实现1.前端2.后端一、验证码的实现
基于你对前后端开发有了一个基础认识之后
1.前端
打开若依RouYi-UI模块,在src/views中的login.vue就是前端的登陆页面,其中
就是验证码的模块,由于验证码是页面初始化的时候就加载了的可以在create中找到主要加载方法
created() {this.getCode();this.getCookie();},
往下在script中可以找到
getCode() {getCodeImg().then(res => {this.captchaEnabled = res.captchaEnabled === undefined ? true : res.captchaEnabled;if (this.captchaEnabled) {this.codeUrl = "data:image/gif;base64," + res.img;this.loginForm.uuid = res.uuid;}});},
其中就是用于接收后端传递的验证码图片和uuid,根据getCodeImg()方法可以找到src\api\login.js下的
// 获取验证码export function getCodeImg() {return request({url: '/captchaImage',headers: {isToken: false},method: 'get',timeout: 20000})}
开启若依进行测试
可以看到url中并没有我们熟悉使用的localhost,可以根据request找到src\utils\request.js下看到熟悉的axios
// 创建axios实例const service = axios.create({// axios中请求配置有baseURL选项,表示请求URL公共部分baseURL: process.env.VUE_APP_BASE_API,// 超时timeout: 10000})
baseURL是VUE工程的一个公共前缀,它的值的定义在配置文件中
这三个是开发、生产、测试环境,我们目前的使用的是开发环境,打开development
# 若依管理系统/开发环境(统一前缀)VUE_APP_BASE_API = '/dev-api'
到这我们看到了/dev-api/的出处,但是我们仍没有看到localhost位置,我们打开vue.config.js可以看到
// webpack-dev-server 相关配置devServer: {host: '0.0.0.0',port: port,open: true,proxy: {// detail: /config/#devserver-proxy[process.env.VUE_APP_BASE_API]: {target: `http://localhost:8080`,//目标changeOrigin: true,pathRewrite: {//路径重写['^' + process.env.VUE_APP_BASE_API]: ''//统一前缀替换成空,然后映射到8080中}}},disableHostCheck: true},
我们看到了8080,它做了一个反向代理,解决了跨域问题,其中进行了路径重写,将我们看到的
http://localhost/dev-api/captchaImage转化成http://localhost:8080/captchaImage
2.后端
我们直接打开ruoyi-admin模块,将我们之前看到的/captchaImage进行搜索(ctrl+shift+f),我们直接定位到CaptchaController
AjaxResult ajax = AjaxResult.success();boolean captchaEnabled = configService.selectCaptchaEnabled();ajax.put("captchaEnabled", captchaEnabled);if (!captchaEnabled){return ajax;}
我们看到它首先创建了一个ajaxResult返回对象,点击进去可以看到若依定义了一个返回类,将结果进行一个封装,然后以统一的格式返回到前端
使用了一个Boolean判断了是否开启了验证码,没有开启便直接返回
// 保存验证码信息String uuid = IdUtils.simpleUUID();String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;String capStr = null, code = null;BufferedImage image = null;
这里定义了一个uuid用来存放放入redis中的后缀,verifyKey用来存放前缀,我们点进CAPTCHA_CODE_KEY中可以看到若依定义了很多redis的key常量,其中captcha_codes就是验证码的key
// 生成验证码String captchaType = RuoYiConfig.getCaptchaType();if ("math".equals(captchaType)){String capText = captchaProducerMath.createText();capStr = capText.substring(0, capText.lastIndexOf("@"));//表达式code = capText.substring(capText.lastIndexOf("@") + 1);//答案image = captchaProducerMath.createImage(capStr);}else if ("char".equals(captchaType)){capStr = code = captchaProducer.createText();image = captchaProducer.createImage(capStr);}
生成验证码,我们了解到若依先是使用kaptcha生成一个类似表达式1+1=?@2,我们可以根据kaptcha查找到在rouyi-framework中framework/config/CaptchaConfig.java和framework/config/KaptchaTextCreator.java若依有关验证码的配置,在KaptchaTextCreator我们可以看到关于验证码的配置是采用=?@的方式进行的,capStr用于存取前边生成的表达式存入(1+1=?),code用于存取表达式的值存入(2),他采用@符号进行分割,将表达式和值进行分开
redisCache.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
缓存,这块就是将verifyKey前缀(key值)和code值(value)放入redis中,后边的Constants.CAPTCHA_EXPIRATION是有效期,点击进入可以看到若依定义的有效期是2,TimeUnit.MINUTES是分钟,所以这个验证码的有效期是两分钟
// 转换流信息写出FastByteArrayOutputStream os = new FastByteArrayOutputStream();try{ImageIO.write(image, "jpg", os);}catch (IOException e){return AjaxResult.error(e.getMessage());}ajax.put("uuid", uuid);ajax.put("img", Base64.encode(os.toByteArray()));
ImageIo将image对象直接写出指定输出流os(把文件写成一张图片),使用toByteArray将os转化为byte数组,然后采用验证码图片工具类 Base64对byte数组进行编码,在前端页面中直接添加data:image/gif;base64,便可以将验证码图片显示出来