当前位置: 首页 > news >正文

芋道源码 - 基于滑块验证码(blockPuzzle), 登录实现

本文记录了在 芋道源码框架 中,如何通过滑块验证码(blockPuzzle)实现安全的登录流程。通过调用验证码服务接口,校验验证码后再执行登录逻辑,防止暴力破解和恶意登录请求。

一、验证码配置

application.yml 中配置验证码参数

#################### 验证码相关配置 ####################
aj:captcha:jigsaw: classpath:images/jigsaw # 滑动验证底图路径pic-click: classpath:images/pic-click # 文字点选底图路径cache-type: redis # 缓存方式 local/rediscache-number: 1000 # local 缓存阈值timing-clear: 180 # 定时清除过期缓存时间(秒)type: blockPuzzle # 验证码类型:blockPuzzle(滑块拼图) | clickWord(文字点选)water-mark: 芋道源码 # 水印文字interference-options: 0 # 滑动干扰项req-frequency-limit-enable: false # 接口请求频率限制开关req-get-lock-limit: 5 # 验证失败次数锁定阈值req-get-lock-seconds: 10 # 锁定时间req-get-minute-limit: 30 # get 接口每分钟请求限制req-check-minute-limit: 60 # check 接口每分钟请求限制req-verify-minute-limit: 60 # verify 接口每分钟请求限制

二、验证码对象模型

CaptchaVO

package com.xingyuv.captcha.model.vo;public class CaptchaVO implements java.io.Serializable {private String captchaId;private String projectCode;private String captchaType;private String captchaOriginalPath;private String captchaFontType;private Integer captchaFontSize;private String secretKey;private String originalImageBase64;private PointVO point;private String jigsawImageBase64;private java.util.List<String> wordList;private java.util.List<java.awt.Point> pointList;private String pointJson;private String token;private Boolean result;private String captchaVerification;private String clientUid;private Long ts;private String browserInfo;
}

PointVO

package com.xingyuv.captcha.model.vo;public class PointVO {private String secretKey;public int x;public int y;
}

三、验证码接口实现

CaptchaController

import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import com.xingyuv.captcha.model.common.ResponseModel;
import com.xingyuv.captcha.model.vo.CaptchaVO;
import com.xingyuv.captcha.service.CaptchaService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;
import javax.annotation.security.PermitAll;
import javax.servlet.http.HttpServletRequest;@Tag(name = "管理后台 - 验证码")
@RestController("adminCaptchaController")
@RequestMapping("/system/captcha")
public class CaptchaController {@Resourceprivate CaptchaService captchaService;@PostMapping("/get")@Operation(summary = "获得验证码")@PermitAllpublic ResponseModel get(@RequestBody CaptchaVO data, HttpServletRequest request) {data.setBrowserInfo(getRemoteId(request));return captchaService.get(data);}@PostMapping("/check")@Operation(summary = "校验验证码")@PermitAllpublic ResponseModel check(@RequestBody CaptchaVO data, HttpServletRequest request) {data.setBrowserInfo(getRemoteId(request));return captchaService.check(data);}public static String getRemoteId(HttpServletRequest request) {String ip = ServletUtils.getClientIP(request);String ua = request.getHeader("user-agent");return (StrUtil.isNotBlank(ip) ? ip : request.getRemoteAddr()) + ua;}
}

四、登录参数对象

AuthLoginReqVO

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AuthLoginReqVO extends CaptchaVerificationReqVO {@Schema(description = "账号(与手机号二选一)", example = "yudaoyuanma")@Length(min = 4, max = 16)@Pattern(regexp = "^[A-Za-z0-9]+$")private String username;@Schema(description = "手机号", example = "13800138000")@Pattern(regexp = "^1[3-9]\\d{9}$")private String mobile;@Schema(description = "密码", example = "buzhidao")@NotEmpty@Length(min = 4, max = 16)private String password;@Schema(description = "社交平台类型", example = "10")private Integer socialType;@Schema(description = "授权码", example = "1024")private String socialCode;@Schema(description = "state", example = "9b2ffbc1-7425-4155-9894-9d5c08541d62")private String socialState;@AssertTrue(message = "用户名或手机号至少填写一个")public boolean isUsernameOrMobilePresent() {return StrUtil.isNotEmpty(username) || StrUtil.isNotEmpty(mobile);}@AssertTrue(message = "授权码不能为空")public boolean isSocialCodeValid() {return socialType == null || StrUtil.isNotEmpty(socialCode);}@AssertTrue(message = "授权 state 不能为空")public boolean isSocialState() {return socialType == null || StrUtil.isNotEmpty(socialState);}
}

五、登录接口

Controller

@PostMapping("/mobile-login")
@PermitAll
@Operation(summary = "使用手机/密码登录")
public CommonResult<AuthLoginRespVO> mobileLogin(@RequestBody @Valid AuthLoginReqVO reqVO) {return success(authService.h5MobileLogin(reqVO));
}

Service 实现

@Override
public AuthLoginRespVO h5MobileLogin(AuthLoginReqVO reqVO) {// 1. 校验验证码validateCaptcha(reqVO);// 2. 校验手机号与密码AdminUserDO user = authenticateMobile(reqVO.getMobile(), reqVO.getPassword());// 3. 社交用户绑定(可选)if (reqVO.getSocialType() != null) {socialUserService.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(),reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState()));}// 4. 登录成功后生成 Tokenreturn createTokenAfterLoginSuccess(user.getId(), reqVO.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME);
}

六、接口调用流程

1️⃣ 获取验证码

URL:

POST https://xxx/admin-api/system/captcha/get

请求体:

{"captchaType": "blockPuzzle", // 滑块类型 (前端传)"clientUid": "slider-44bd2b7a-3443-4823-8a60-5cf680ca05ba", // 唯一标识(前端传)"ts": 1760775769847 // 时间戳(前端传)
}

参数名来源示例值说明
captchaType前端传入(固定值)"blockPuzzle"验证码类型。可选值包括 blockPuzzle(滑块拼图) 和 clickWord(文字点选)。前端根据需要指定。
clientUid前端生成"slider-44bd2b7a-3443-4823-8a60-5cf680ca05ba"客户端唯一标识,用于区分不同用户或设备的验证码会话。前端一般使用 UUID 或随机字符串生成,整个验证码流程中保持不变。
ts前端生成1760775769847时间戳(毫秒),用于标识请求发起时间,防止接口缓存或重复请求。一般使用 Date.now() 生成。

响应示例:

{"repCode": "0000","repData": {"secretKey": "VczzXIMcPK3o3I0M","originalImageBase64": "Base64背景图","jigsawImageBase64": "Base64滑块图","token": "c6b9ff2bdd8d4735b8699f5fbe3201ec"},"success": true
}

2️⃣ 校验验证码

URL:

POST https://xxx/admin-api/system/captcha/check

请求体:

{"captchaType": "blockPuzzle","pointJson": "0Np587J0fyWkJB/Kjx7NNlHa8K8nplSaJon2xNDt4UM=", // 用户拖动后滑块的坐标信息(加密)"token": "baf157e8395d44758e44a27c1c4dac39"
}

参数名生成方说明
captchaType前端固定写死验证码类型
pointJson✅ 前端根据拖动坐标 + secretKey 加密生成滑块位置验证核心参数
token✅ 后端 /captcha/get 返回校验验证码时使用的唯一标识

响应示例:

{"repCode": "0000","repData": {"captchaType": "blockPuzzle","result": true},"success": true
}

3️⃣ 执行登录

URL:

POST https://xxx/admin-api/h5/exam/user/mobile-login

请求体:

{"mobile": "185xxx","password": "123456","captchaVerification": "zFuzN8EXE6mO+UNBmWdwSoEUcbCZqUrbkMhUM5Em6CwPJikXFgCTuu6wWDj35xTnOgX2igMiTqjiX9rG3ycFNOsQfxwJWu1/p1QKzcW9mNE="
}

参数名来源示例值说明
mobile前端输入"账号"用户的手机号,由用户在登录页面输入。
password前端输入"密码"用户密码,由用户在登录页面输入。一般会在前端或传输层(HTTPS)加密传输。
captchaVerification前端传入(由验证码组件生成)"zFuzN8EXE6mO+UNBmWdwSoEUcbCZqUrbkMhUM5Em6CwPJikXFgCTuu6wWDj35xTnOgX2igMiTqjiX9rG3ycFNOsQfxwJWu1/p1QKzcW9mNE="验证码二次校验凭证(加密字符串)。用户在滑动或点选验证码成功后,前端会从验证码组件中拿到该加密结果,并传给后台。后台通过此字段验证验证码是否通过。

响应示例:

{"code": 0,"data": {"userId": 173,"accessToken": "8ec0c0b171424a5ea0d92931e051b47d","refreshToken": "5a63eefc570c49fda9247a2537e99284","expiresTime": 1760777570708},"msg": "操作成功"
}

七、整体流程总结

步骤接口描述
1/system/captcha/get获取滑块验证码(返回背景图与滑块图)
2/system/captcha/check校验滑块位置正确性
3/h5/exam/user/mobile-login校验验证码成功后登录

八、优点

✅ 安全防刷:通过滑块验证避免暴力破解。
✅ 前后端分离:前端完成拖动逻辑,后端只负责校验。
✅ 兼容性强:支持多类型验证码(滑块、文字点选)。
✅ 扩展性好:可切换缓存类型(local / redis)。

http://www.dtcms.com/a/500617.html

相关文章:

  • 网站关键词优化报价新泰网站开发制作
  • flash静态网站怎么做个人网页
  • Milvus的可视化工具Attu安装
  • 网站备案需要拍照如何建立网站建设规划
  • 【LLIE技术专题】LiteIE :超轻量级无监督低光图像增强框架
  • 百度抓取不到网站网站配色
  • USB -- SET_ADDRESS or --SET_ADDRESS or --SET_CONFIGURATION or --SET_INTERFACE
  • DeepSeek-7B-chat 4bits量化 QLora 微调
  • 遥测服务技术
  • 上虞网站建设文广网络石家庄网络推广公司排名
  • 网站seo模块怎么才能在百度上搜到自己的网站
  • 建设网站要用什么软件做视频网站需要多大带宽
  • 春招准备之Linux系统篇
  • 国际网站空间南京专业app开发定制
  • Qt 控件 QSS 样式大全(控件特性篇)
  • 建设网站的主要流程有哪些wordpress数据库搜索功能
  • ICT 数字测试原理 28 - -如何在测试中使用PCF
  • 肤契:全域协议版 I
  • 重庆公司社保开户流程杭州企业网站优化
  • 站长之家新网址研学网站平台建设方案
  • 南乐网站建设价格wordpress摘要
  • 进制之间的转换
  • python|数值类型
  • 西宁北京网站建设南阳公司注册
  • 京东网站建设哪家好受欢迎的模板网站建设
  • 汉口网站建设公司福田做网站公司
  • 做外贸怎样上国外网站做一个软件要多少钱
  • 沂源网站建设yx718用dw做网站首页
  • 手机怎么做钓鱼网站邯山专业做网站
  • Kafka零拷贝原理深度解析:从传统拷贝痛点到工作实践优化