简述:
在web开发中验证码是一个常见的功能。不论是防止机器人还是爬虫都有一定的作用,我们可以自己编写验证码的工具类,也可以使用比较方便的验证码工具。

本文使用Spring boot 集成 Kaptcha 实现前后端分离验证码功能,这里为什么强调前后端分离,拿登陆功能为例,在登陆我们要请求后台返回一张验证码图片,然后输入用户名密码加上验证码,再次提交给后台,如果不是前后端分离,可轻松的从session中获取用户信息;现在前后端分离了,session失效了,第二次请求认为是一个新的用户,这问题就产生了,我们不能确定当前传过的这个验证码是否是第一次给这个用户的,本文就是要解决这个问题,在前后端分离项目中实现验证码校验功能。

解决思路:
1、前端请求后端,后端返回验证码图片和TOKEN。
2、后端将TOKEN和验证码记录在数据库中。
3、前端请求登陆,传入TOKEN和验证码及相关登陆信息,让后端匹配验证码。
4、后端按TOKEN查出验证码,对刚传入的验证码进行匹配。
5、匹配成功,登陆成功;匹配失败,返回异常信息。

具体实现:
一、首先,搭建一个Spring boot 工程,在我博客中可以找到具体的搭建文章。
二、导入kaptcha的依赖

<dependency>  <groupId>com.github.penggle</groupId>  <artifactId>kaptcha</artifactId>  <version>2.3.2</version>
</dependency>

三、配置kaptcha

/*** 生成验证码配置** @author shanming.yang* @email a78270528@126.com* @date 2017-04-20 19:22*/
@Configuration
public class KaptchaConfig {@Beanpublic DefaultKaptcha producer() {Properties properties = new Properties();properties.put("kaptcha.border", "no");properties.put("kaptcha.textproducer.font.color", "black");properties.put("kaptcha.textproducer.char.space", "10");properties.put("kaptcha.textproducer.char.length","4");properties.put("kaptcha.image.height","34");properties.put("kaptcha.textproducer.font.size","25");properties.put("kaptcha.noise.impl","com.google.code.kaptcha.impl.NoNoise");Config config = new Config(properties);DefaultKaptcha defaultKaptcha = new DefaultKaptcha();defaultKaptcha.setConfig(config);return defaultKaptcha;}
}

四、后端创建请求验证码接口

1、请求验证码接口

 @ResponseBody@RequestMapping(value = "/captcha", method = RequestMethod.POST)public Map<String, Object> captcha(HttpServletResponse response) throws ServletException, IOException {// 生成文字验证码String text = producer.createText();// 生成图片验证码ByteArrayOutputStream outputStream = null; BufferedImage image = producer.createImage(text);outputStream = new ByteArrayOutputStream();  ImageIO.write(image, "jpg", outputStream);  // 对字节数组Base64编码  BASE64Encoder encoder = new BASE64Encoder();  // 生成captcha的tokenMap<String, Object> map = captchaService.createToken(text);map.put("img", encoder.encode(outputStream.toByteArray()));return map;}

2、登陆接口

   /*** 登录*/@IgnoreAuth@PostMapping("login")@ApiOperation(value = "登录",notes = "登录")@ApiImplicitParams({@ApiImplicitParam(paramType = "query", dataType="string", name = "account", value = "账号", required = true),@ApiImplicitParam(paramType = "query", dataType="string", name = "password", value = "密码", required = true),@ApiImplicitParam(paramType = "query", dataType="string", name = "captcha", value = "验证码", required = true)})public R login(HttpServletRequest request,String account, String password,String captcha,String ctoken){Assert.isBlank(account, "账号不能为空");Assert.isBlank(password, "密码不能为空");Assert.isBlank(password, "验证码不能为空");String token = request.getHeader("token");CaptchaEntity captchaEntity  = captchaService.queryByToken(ctoken);if(!captcha.equalsIgnoreCase(captchaEntity.getCaptcha())){return R.error("验证码不正确");}//用户登录String userId = userService.login(account, password);//生成tokenMap<String, Object> map = tokenService.createToken(userId);return R.ok(map);}

3、具体实现

@Service("captchaService")
public class CaptchaServiceImpl implements CaptchaService {@Autowiredprivate CaptchaDao captchaDao;//1小时后过期private final static int EXPIRE = 3600 * 1;@Overridepublic CaptchaEntity queryByCaptcha(String captcha) {return captchaDao.queryByCaptcha(captcha);}@Overridepublic CaptchaEntity queryByToken(String token) {return captchaDao.queryByToken(token);}@Overridepublic void save(CaptchaEntity token){captchaDao.save(token);}@Overridepublic void update(CaptchaEntity token){captchaDao.update(token);}@Overridepublic boolean isExpired(Date expireTime){Date d=new Date();return d.getTime()>expireTime.getTime()?true:false;}@Overridepublic Map<String, Object> createToken(String captcha) {//生成一个tokenString token = UUID.randomUUID().toString();//当前时间Date now = new Date();//过期时间Date expireTime = new Date(now.getTime() + EXPIRE * 1000);//判断是否生成过tokenCaptchaEntity tokenEntity = queryByCaptcha(captcha);if(tokenEntity == null){tokenEntity = new CaptchaEntity();tokenEntity.setCaptcha(captcha);tokenEntity.setToken(token);tokenEntity.setUpdateTime(now);tokenEntity.setExpireTime(expireTime);//保存tokensave(tokenEntity);}else{tokenEntity.setToken(token);tokenEntity.setUpdateTime(now);tokenEntity.setExpireTime(expireTime);//更新tokenupdate(tokenEntity);}Map<String, Object> map = new HashMap<>();map.put("token", token);map.put("expire", EXPIRE);return map;}@Overridepublic void deleteByToken(String token) {captchaDao.deleteByToken(token);}
}

4、DAO

/*** 验证码* * @author shanming.yang* @email a78270528@126.com* @date 2017-11-22 15:22:07*/
public interface CaptchaDao extends BaseDao<CaptchaEntity> {CaptchaEntity queryByCaptcha(String captcha);CaptchaEntity queryByToken(String token);void deleteByToken(String token);}

5、Mapper

<mapper namespace="com.fingerprint.dao.TokenDao"><select id="queryByUserId" resultType="com.fingerprint.entity.TokenEntity">select * from u_token where user_id = #{value}</select><select id="queryByToken" resultType="com.fingerprint.entity.TokenEntity">select * from u_token where token = #{value}</select><insert id="save" parameterType="com.fingerprint.entity.TokenEntity">insert into u_token(`user_id`, `token`, `expire_time`, `update_time`)values(#{userId}, #{token}, #{expireTime}, #{updateTime})</insert><update id="update" parameterType="com.fingerprint.entity.TokenEntity">update u_token <set><if test="token != null">`token` = #{token}, </if><if test="expireTime != null">`expire_time` = #{expireTime}, </if><if test="updateTime != null">`update_time` = #{updateTime}</if></set>where user_id = #{userId}</update><delete id="deleteByToken">delete from u_token where token = #{value}</delete></mapper>

五、前端AJAX(VUE)

login: function (event) {
//alert(localStorage.getItem("ctoken"));
var data = "account="+vm.username+"&password="+vm.password+"&captcha="+vm.captcha+"&ctoken="+localStorage.getItem("ctoken");
$.ajax({type: "POST",url: basePath+"api/login",headers:{'token':localStorage.getItem("token")},data: data,dataType: "json",success: function(result){//alert(result.code);if(result.code == 0){//登录成功var token=result.token;var expire=result.expire;localStorage.setItem("token",token);parent.location.href = 'sysindex.html';}else{vm.error = true;vm.errorMsg = result.msg;vm.refreshCode();}}
});
function ajaxcaptcha(){$.ajax({type: "POST",url: basePath+"captcha",dataType: "json",success: function(result){//JQUERY//$("#captchaimg").prop('src', 'data:image/jpeg;base64,'+result.img);localStorage.setItem("ctoken",result.token);vm.src = 'data:image/jpeg;base64,'+result.img;}});
}

六、前端HTML页面

<div class="form-group has-feedback"><img id="captchaimg" alt="如果看不清楚,请单击图片刷新!" class="pointer" :src="src"  @click="refreshCode"><a href="javascript:;" @click="refreshCode">{{$t("refresh")}}</a></div>

七、注意

生成的Base64编码前要加入data:image/jpeg;base64,可通过http://imgbase64.duoshitong.com/来判断生成的Base64图片是否正确,粘入代码,如果正确,会显示对应图片,否则生成Base64错误。(感谢同事小岳岳的帮助)

到此,使用Spring boot 集成 Kaptcha 实现前后端分离验证码功能已完成。

Spring boot 集成 Kaptcha 实现前后端分离验证码功能相关推荐

  1. 记一次Spring boot 和Vue的前后端分离的入门培训

    记一次Spring boot 和Vue的前后端分离的入门培训 由于公司之前是写C#的,现在要转 Java分布式 + vue,所以进行一次前后端的简单培训. 前端工具和环境: Node.js V10.1 ...

  2. 基于Spring boot + Mybatis +Netty 实现前后端分离的聊天App,部署到阿里云线上服务器...

    前后端分离Spring boot 项目部署 了解前后端分离项目 配置云服务器 java maven tomcat nginx mysql 部署后端项目 部署前端项目 部署Java环境 1.下载JDK软 ...

  3. 鸿鹄工程项目管理系统 Spring Cloud+Spring Boot+Mybatis+Vue+ElementUI+前后端分离构建工程项目管理系统

    鸿鹄工程项目管理系统 Spring Cloud+Spring Boot+Mybatis+Vue+ElementUI+前后端分离构建工程项目管理系统 1. 项目背景 一.随着公司的快速发展,企业人员和经 ...

  4. Spring Boot + Vue.js 实现前后端分离(附源码)

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 作者: 梁小生0101 链接:juejin.im/post/5c6 ...

  5. Spring Boot + Vue + Shiro 实现前后端分离、权限控制

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 来源:http://sina.lt/gauR 本文总结自实习中对项 ...

  6. Java Spring boot element ui activiti前后端分离,流程审批,权限管理框架

    基于react ant design pro typescript 技术框架已经重磅推出 预览地址 系统介绍 是什么? 使用springboot,activiti,mybatis,vue elemen ...

  7. Spring Boot + Vue + Shiro 实现前后端分离、权限控制 (附源码)

    点击上方[全栈开发者社区]→右上角[...]→[设为星标⭐] 原项目采用Springboot+freemarker模版,开发过程中觉得前端逻辑写的实在恶心,后端Controller层还必须返回Free ...

  8. VUE+Spring Boot整合MyBatis实现前后端分离项目壁纸网站

    目录 前言 一.项目运行 二.环境需要 三.技术栈 四.项目说明 五.后端代码 前言 每次换桌面,壁纸总是不好找,搜索图片得不到好的索引与反馈,很难找到自己喜欢的壁纸,而壁纸网站可以免去我们去寻找壁纸 ...

  9. Docker中Spring boot+VueJS+MongoDB的前后端分离哲学摔跤

    一图胜千言 目标 想将VueJs,Spring boot,MongoDB全部都放到Docker中运行,并且做到VueJs和Spring boot在不同都Docker容器中. Docker带来的变化 开 ...

  10. 企业电子招标采购系统源码Spring Cloud + Spring Boot + MybatisPlus + Redis + Layui + 前后端分离 + 二次开发

    项目说明 随着公司的快速发展,企业人员和经营规模不断壮大,公司对内部招采管理的提升提出了更高的要求.在企业里建立一个公平.公开.公正的采购环境,最大限度控制采购成本至关重要.符合国家电子招投标法律法规 ...

最新文章

  1. 王飞跃谈GE艰难的数字化转型启示:从工业智联网到工业5.0
  2. 全国大学生智能汽车竞赛 --智慧物流创意组
  3. 关于学生信息录入(文件操作)的心得体会
  4. error C2660: 'MessageBoxA' : function does not take 4 parameters
  5. H - Great Cells Gym - 101194H(数学推导/思维)
  6. Kibana入门安装与介绍
  7. 输入框回车多个文本_输入框测试用例,你真的了解输入框测试嘛!
  8. JAVA-java内存分配
  9. python爬虫代码-python网络爬虫源代码(可直接抓取图片)
  10. PHP两种redirect
  11. 特斯拉,谁给你的勇气在中国玩双标
  12. 因为链接服务器 IP 的 OLE DB 访问接口 SQLNCLI 无法启动分布式事务
  13. 蓝桥杯题目练习 水题 [蓝桥杯2019初赛]质数
  14. 线性代数辅导讲义(第六章 二次型)
  15. SCI文献参考基本格式(全)
  16. signature=0805b6a4f11b6551d9a746082990b689,Derived certificate based on changing identity
  17. 计算机主机的储存,电脑截屏保存在哪里 电脑截屏保存位置【图文】
  18. 【SpringCloud 2021.0.0】12、路由网关Gateway之简介 (spring-boot 2.6.3)
  19. linux 合并多个pdf,Linux 下合并 PDF
  20. 【表面缺陷检测】基于yolov5的布匹表面缺陷检测(附代码和数据集)

热门文章

  1. IT运维面试问题总结
  2. 【手把手】ElasticSearch的搜索推荐相关
  3. 2021届的Java后端应届生面试总结
  4. 雷顿学院《百万大咖》校园行
  5. 罗马数字转换python_Python简单实现阿拉伯数字和罗马数字的互相转换功能示例
  6. 手机影像ISP流程:AWB(1)
  7. Android 显示大尺寸图片
  8. java实现随机游走算法_java – 简单的2D随机游走
  9. selenium:如何模拟鼠标拖放(drag and drop)
  10. “中国会员电商第一股”云集的反爬虫攻防战 | 产业安全专家谈