java 登录滑动验证码功能实现
- spring boot使用版本
org.springframework.boot spring-boot-starter-parent 3.2.0 2.pom.xml依赖包
<!-- Spring Web --> org.springframework.boot spring-boot-starter-web <!-- 验证码框架导入 --> cloud.tianai.captcha tianai-captcha-springboot-starter 1.5.5 <!-- 引用web前端框架 --> org.springframework.boot spring-boot-starter-thymeleaf org.projectlombok lombok true 3.application.yml验证码配置

# 行为验证码配置, 详细请看 cloud.tianai.captcha.autoconfiguration.ImageCaptchaProperties 类captcha: # 如果项目中使用到了redis,滑块验证码会自动把验证码数据存到redis中, 这里配置redis的key的前缀,默认是captcha:slider prefix: captcha # 验证码过期时间,默认是2分钟,单位毫秒, 可以根据自身业务进行调整 expire: # 默认缓存时间 2分钟 default: 10000 # 针对 点选验证码 过期时间设置为 2分钟, 因为点选验证码验证比较慢,把过期时间调整大一些 WORD_IMAGE_CLICK: 20000 # 使用加载系统自带的资源, 默认是 false(这里系统的默认资源包含 滑动验证码模板/旋转验证码模板,如果想使用系统的模板,这里设置为true) init-default-resource: true # 缓存控制, 默认为false不开启 local-cache-enabled: false # 缓存开启后,验证码会提前缓存一些生成好的验证数据, 默认是20 local-cache-size: 20 # 缓存开启后,缓存拉取失败后等待时间 默认是 5秒钟 local-cache-wait-time: 5000 # 缓存开启后,缓存检查间隔 默认是2秒钟 local-cache-period: 2000 # 缓存开启后,忽略的字段,默认是 ""(不忽略任何字段) local-cache-ignored-cache-fields: "" # 配置字体包,供文字点选验证码使用,可以配置多个,不配置使用默认的字体 font-path: - classpath:font/SimHei.ttf secondary: # 二次验证, 默认false 不开启 enabled: false # 二次验证过期时间, 默认 2分钟 expire: 120000 # 二次验证缓存key前缀,默认是 captcha:secondary keyPrefix: "captcha:secondary"4.配置验证码资源存储器
import cloud.tianai.captcha.common.constant.CaptchaTypeConstant;import cloud.tianai.captcha.resource.ResourceStore;import cloud.tianai.captcha.resource.impl.LocalMemoryResourceStore;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import cloud.tianai.captcha.resource.common.model.dto.Resource;@Configurationpublic class CaptchaResourceConfiguration { /** * 配置验证码资源存储器 * @return ResourceStore */ @Bean public ResourceStore resourceStore() { // 使用简单的本地内存存储器,实际项目中可以使用数据库等存储 LocalMemoryResourceStore resourceStore = new LocalMemoryResourceStore(); // 配置背景图 // arg1: 验证码类型(SLIDER、ROTATE、CONCAT、WORD_IMAGE_CLICK) // arg2: Resource对象,包含: 资源类型(calsspath、file、url)、文件路径、tag标签 resourceStore.addResource(CaptchaTypeConstant.SLIDER, new Resource("classpath", "bgimages/a.jpg", "default")); resourceStore.addResource(CaptchaTypeConstant.SLIDER, new Resource("classpath", "bgimages/b.jpg", "default")); resourceStore.addResource(CaptchaTypeConstant.SLIDER, new Resource("classpath", "bgimages/c.jpg", "default")); resourceStore.addResource(CaptchaTypeConstant.ROTATE, new Resource("classpath", "bgimages/48.jpg", "default")); resourceStore.addResource(CaptchaTypeConstant.CONCAT, new Resource("classpath", "bgimages/48.jpg", "default")); resourceStore.addResource(CaptchaTypeConstant.WORD_IMAGE_CLICK, new Resource("classpath", "bgimages/c.jpg", "default")); return resourceStore; }}5.验证码controller类
import cloud.tianai.captcha.application.ImageCaptchaApplication;import cloud.tianai.captcha.application.vo.ImageCaptchaVO;import cloud.tianai.captcha.common.constant.CaptchaTypeConstant;import cloud.tianai.captcha.common.response.ApiResponse;import cloud.tianai.captcha.generator.common.model.dto.GenerateParam;import cloud.tianai.captcha.spring.plugins.secondary.SecondaryVerificationApplication;import cloud.tianai.captcha.validator.common.model.dto.ImageCaptchaTrack;import jakarta.servlet.http.HttpServletRequest;import lombok.Data;import org.apache.commons.lang3.StringUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;import java.util.Collections;import java.util.concurrent.ThreadLocalRandom;@RestControllerpublic class CaptchaController { @Autowired private ImageCaptchaApplication imageCaptchaApplication; @RequestMapping("/gen") @ResponseBody public ApiResponse genCaptcha(HttpServletRequest request, @RequestParam(value = "type", required = false)String type) { if (StringUtils.isBlank(type)) { type = CaptchaTypeConstant.SLIDER; } if ("RANDOM".equals(type)) { int i = ThreadLocalRandom.current().nextInt(0, 4); if (i == 0) { type = CaptchaTypeConstant.SLIDER; } else if (i == 1) { type = CaptchaTypeConstant.CONCAT; } else if (i == 2) { type = CaptchaTypeConstant.ROTATE; } else{ type = CaptchaTypeConstant.WORD_IMAGE_CLICK; } } GenerateParam generateParam = new GenerateParam(); // 要生成的验证码类型 generateParam.setType(type); ApiResponse response = imageCaptchaApplication.generateCaptcha(generateParam); return response; } @PostMapping("/check") @ResponseBody public ApiResponse<!--?--> checkCaptcha(@RequestBody Data data, HttpServletRequest request) { ApiResponse<!--?--> response = imageCaptchaApplication.matching(data.getId(), data.getData()); if (response.isSuccess()) { return ApiResponse.ofSuccess(Collections.singletonMap("id", data.getId())); } return response; } @lombok.Data public static class Data { private String id; private ImageCaptchaTrack data; } /** * 二次验证,一般用于机器内部调用,这里为了方便测试 * @param id id * @return boolean */ @GetMapping("/check2") @ResponseBody public boolean check2Captcha(@RequestParam("id") String id) { // 如果开启了二次验证 if (imageCaptchaApplication instanceof SecondaryVerificationApplication) { return ((SecondaryVerificationApplication) imageCaptchaApplication).secondaryVerification(id); } return false; }} 6.登录类
import cloud.tianai.captcha.application.ImageCaptchaApplication;import cloud.tianai.captcha.spring.plugins.secondary.SecondaryVerificationApplication;import jakarta.servlet.http.HttpSession;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.*;import java.util.HashMap;import java.util.Map;@Controller//@CrossOrigin(origins = "*")public class LoginController { @Autowired private ImageCaptchaApplication imageCaptchaApplication; // 模拟账号密码 private static final String USERNAME = "admin"; private static final String PASSWORD = "123456"; /** * 登录页面 * @param model * @return */ @RequestMapping(value="/login",method = RequestMethod.GET) public String getLogin(Model model){ return "login"; } /** * 欢迎页面 * @param model * @return */ @RequestMapping(value="/home",method = RequestMethod.GET) public String getHome(Model model){ return "home"; } /** * 3. 登录接口(必须先通过滑块验证) */ @PostMapping("/login") @ResponseBody public Map login( @RequestParam String username, @RequestParam String password, @RequestParam String token, // 图片验证码token HttpSession session) { Map result = new HashMap<>(); result.put("success", false); // 1. 校验滑块是否验证 // 如果开启了二次验证 if (imageCaptchaApplication instanceof SecondaryVerificationApplication) { boolean codeSuccess=((SecondaryVerificationApplication) imageCaptchaApplication).secondaryVerification(token); if (!codeSuccess){ result.put("msg", "请先完成滑动验证!"); return result; } } // 2. 非空校验 if (username.isEmpty() || password.isEmpty()) { result.put("msg", "请输入用户名/密码"); return result; } // 3. 账号密码校验 if (USERNAME.equals(username) && PASSWORD.equals(password)) { result.put("success", true); result.put("msg", "登录成功"); } else { result.put("msg", "用户名或密码错误"); } return result; } @PostMapping("/logout") @ResponseBody public Map logout(HttpSession session) { session.invalidate(); // 清空所有Session Map result = new HashMap<>(); result.put("success", true); result.put("msg", "退出成功"); return result; }} 7.前端登录login.html
滑动验证码登录 [xss_clean][xss_clean] [xss_clean][xss_clean] <!-- 装载验证码的DIV --> 用户登录
[xss_clean] function login(token) { let username = document.getElementById("username").value; let password = document.getElementById("password").value; fetch("/login", { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: `username=${username}&password=${password}&token=${token}` }) .then(res => res.json()) .then(data => { if (data.success) { location.href = "/home?username="+username; }else{ alert(data.msg); } }); } // 4. 登录提交 function submitLogin() { const captchaConfig = { // 生成接口 (必选项,必须配置, 要符合tianai-captcha默认验证码生成接口规范) // 正确返回的数据结构: {code:200, data:{}} // 异常返回的数据结构: {code:500, msg:'xxx'} requestCaptchaDataUrl: "/gen?type=SLIDER", // 验证接口 validCaptchaUrl: "/check", // 验证码绑定的div块 bindEl: "#captcha-box", // 验证成功回调函数(必选项,必须配置) validSuccess: (res, c, t) => { console.log("验证码验证成功回调..."); // 销毁验证码组件 t.destroyWindow(); // 调用具体的业务方法 login(res.data.token); }, // 验证失败的回调函数(可忽略,如果不自定义 validFail 方法时,会使用默认的) validFail: (res, c, t) => { console.log("验证码验证失败回调..."); // 验证失败后重新拉取验证码 t.reloadCaptcha(); }, // 刷新按钮回调事件 btnRefreshFun: (el, tac) => { console.log("刷新按钮触发事件..."); tac.reloadCaptcha(); }, // 关闭按钮回调事件 btnCloseFun: (el, tac) => { console.log("关闭按钮触发事件..."); tac.destroyWindow(); } }; // 一些样式配置, 可不传 const style = { // logoUrl: "..." }; // 创建 TAC 启动验证码服务 new TAC(captchaConfig, style).init(); }[xss_clean]8.效果图
9.源码下载
https://gitee.com/rang/silder-validate-demo.git
文章版权声明:除非注明,否则均为边学边练网络文章,版权归原作者所有