Spring boot 集成 Kaptcha 实现前后端分离验证码功能
来源:互联网 发布:java goto特殊功能 编辑:程序博客网 时间:2024/05/22 14:58
简述:
在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 */@Configurationpublic 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", "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); //生成token Map<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 实现前后端分离验证码功能
- Spring MVC+Kaptcha实现验证码功能
- SpringBoot–集成验证码kaptcha实现验证码功能
- spring和angularJS实现前后端分离
- spring boot 前后端分离,解决ajax跨域问题
- Kaptcha实现的验证码功能
- struts2使用kaptcha实现验证码功能
- springMVC Kaptcha 实现验证码功能
- spring vue 前后端分离
- springboot集成kaptcha验证码
- 前后端分离项目shiro验证
- springMVC入门(四) Kaptcha 实现验证码功能
- jfinal整合kaptcha实现验证码功能简单Demo
- springMVC入门(四) Kaptcha 实现验证码功能
- 基于google插件Kaptcha实现图片验证码功能
- Spring 验证码(kaptcha)
- spring kaptcha 验证码使用
- Spring Boot 菜鸟教程 9 swagger-前后端分离后的标准
- “最能激怒程序员的那些话”——十大排行榜
- ubuntu安装openssh-server开启远程连接
- POJ——Problem1163(三角形动态规划)
- Android 软键盘弹出情况下监听返回键直接退出界面
- 作为Unity程序员需要掌握的技能
- Spring boot 集成 Kaptcha 实现前后端分离验证码功能
- JetBrains IntelliJ IDEA Ultimate 2017.2.5 官方旗舰版 windows/mac/Linux
- Zookeeper知识点总结
- 深度学习(十)之序列建模:循环和递归网络①
- Android设计模式--建造者模式
- 23种设计模式全解析
- 模糊查找排序
- js 实现ReplaceAll(包含加号、减号的处理)
- Android layout属性大全