1. 验证码案例
随着安全性的要求越来越高,目前项目中很多都使用了验证码,验证码的形式也是多种多样,更复杂的图形验证码和⾏为验证码已经成为了更流⾏的趋势.
2. 需求
界面如下图所示
1. 页面生成验证码
2. 输入验证码,点击提交,验证用户输入验证码是否正确,正确则进行页面跳转
3. 准备工作
创建项⽬,引⼊SpringMVC的依赖包,把前端页面放在项目中.
导入依赖
Hutool🍬一个功能丰富且易用的Java工具库,涵盖了字符串、数字、集合、编码、日期、文件、IO、加密、数据库JDBC、JSON、HTTP客户端等功能。插件的依赖
<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-captcha -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-captcha</artifactId>
<version>5.8.20</version>
</dependency>
4. 接口定义
- 生成验证码
url: /captcha/get
param(参数): 无
Return: 图片的内容
- 校验验证码
url: /captcha/check
param: inputCode (用户输入的验证码)
return: true / false
5. 代码编写
生成验证码:
@RequestMapping("/captcha")
@RestController
public class CaptchaController {@RequestMapping("/get")public void getCaptcha(HttpServletResponse response) {LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(200,100);//图型验证码写出,可以写出到文件,也可以写出到流try {lineCaptcha.write(response.getOutputStream()); //返回到浏览器} catch (IOException e) {throw new RuntimeException(e);}}
}
修改前端代码相对应的接口
验证成功
校验验证码
校验前端用户输入返回的验证码是否正确
问题: 会有多个用户同时访问,就要考虑多线程问题,得到的验证码就不能放到同一个变量里
解决方法: 把每个不同用户生成的验证码放到与之相对应的session里储存
//图型验证码写出,可以写出到文件,也可以写出到流try {lineCaptcha.write(response.getOutputStream()); //返回到浏览器//得到函数生成的验证码String code = lineCaptcha.getCode(); //得到函数生成的验证码//存储到session//必须考虑到多线程访问,因为有多个用户访问,把每个用户生成的code存放到对应用户的session里面session.setAttribute("captcha_session_key", code);//获取一个时间戳存入session,来设置验证码的有效期(这是得到设置code的时间戳)session.setAttribute("captcha_session_data",new Date());} catch (IOException e) {throw new RuntimeException(e);}
取出用户session里的验证码与用户输入的验证码匹配,符合的话就返回true
还添加了验证码过期的功能
@RequestMapping("/captcha")
@RestController
public class CaptchaController {private final static long session_valid_timeout = 60*1000;@Autowiredprivate CaptchaProperties captchaProperties;@RequestMapping("/get")public void getCaptcha(HttpSession session, HttpServletResponse response) {LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(captchaProperties.getWidth(),captchaProperties.getHeight());//图型验证码写出,可以写出到文件,也可以写出到流try {lineCaptcha.write(response.getOutputStream()); //返回到浏览器//得到函数生成的验证码String code = lineCaptcha.getCode(); //得到函数生成的验证码//存储到session//必须考虑到多线程访问,因为有多个用户访问,把每个用户生成的验证码存放到对应用户的session里面session.setAttribute(captchaProperties.getSession().getKey(), code);//获取一个时间戳存入session,来设置验证码的有效期(这是得到设置code的时间戳)session.setAttribute(captchaProperties.getSession().getDate(),new Date());response.getOutputStream().close();} catch (IOException e) {throw new RuntimeException(e);}}@RequestMapping("/check")public boolean check(String inputCode, HttpSession session) {//验证码生成的内容和用户输入的内容进行比较if (!StringUtils.hasLength(inputCode)) { //如果为空return false;}//从session获取信息String saveCode = (String) session.getAttribute(captchaProperties.getSession().getKey()); //前端页面生成的验证码Date saveData = (Date) session.getAttribute(captchaProperties.getSession().getDate());if(inputCode.equalsIgnoreCase(saveCode)) { //忽略大小写进行判断//判断验证码是否过期if (saveData != null && System.currentTimeMillis()-saveData.getTime() < session_valid_timeout){return true;}}return false;}
}