介紹
滑塊驗證碼比傳統的字符驗證碼更加直觀和用戶友好,能夠很好防止爬蟲獲取數據。
AJ-Captcha行為驗證碼,包含滑動拼圖、文字點選兩種方式,UI支持彈出和嵌入兩種方式。后端提供Java實現,前端提供了php、angular、html、vue、uni-app、flutter、android、ios等代碼示例。
開源地址: https://gitee.com/anji-plus/captcha
官方文檔: https://ajcaptcha.beliefteam.cn/captcha-doc
效果圖
依賴
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency><dependency><groupId>com.anji-plus</groupId><artifactId>captcha-spring-boot-starter</artifactId><version>1.4.0</version>
</dependency>
Redis配置
spring:redis:host: 127.0.0.1port: 6379password:database: 1timeout: 6000
驗證碼配置
aj:captcha:# 滑動驗證底圖路徑,不配置將使用默認圖片jigsaw: classpath:images/jigsaw# 滑動驗證底圖路徑,不配置將使用默認圖片pic-click: classpath:images/pic-click# 緩存類型設置,默認使用local緩存cache-type: redis# local緩存的閾值, 達到此值后清除緩存cache-number: 1000# local定時清除過期緩存(單位秒), 設置為0表示不執行timing-clear: 180# 驗證碼類型,default代表兩種都實例化type: default# 右下角水印文字,使用Unicode表示# 漢字統一使用Unicode,保證程序通過@value讀取到是中文,可通過這個在線轉換;yml格式不需要轉換# https://tool.chinaz.com/tools/unicode.aspx 中文轉Unicodewater-mark: "\u6211\u7684\u6c34\u5370" # Unicode: 我的水印# 水印字體(可選配置,默認為文泉驛正黑)# water-font: WenQuanZhengHei.ttf# 滑動拼圖允許的誤差偏移量(默認5像素)slip-offset: 5# AES加密坐標開啟或者禁用 (true 或 false)aes-status: true# 滑動驗證干擾項配置 (0、1、2)interference-options: 2# 點選驗證碼字體樣式 (默認Font.BOLD)font-style: 1# 點選字體的大小font-size: 25# 歷史數據清除配置,是否啟用history-data-clear-enable: false# 接口請求頻率限制配置req-frequency-limit-enable: false# 驗證失敗次數達到限制后,get接口將被鎖定req-get-lock-limit: 5# 驗證失敗后,鎖定時間間隔(秒)req-get-lock-seconds: 360# get接口一分鐘內請求次數限制req-get-minute-limit: 30# check接口一分鐘內請求次數限制req-check-minute-limit: 60# verify接口一分鐘內請求次數限制req-verify-minute-limit: 60
配置類
@Configuration
@RequiredArgsConstructor
public class CaptchaConfig {private final StringRedisTemplate redisTemplate;@Bean(name = "AjCaptchaCacheService")@Primarypublic CaptchaCacheService captchaCacheService(AjCaptchaProperties config){//緩存類型redis/local/....CaptchaCacheService ret = CaptchaServiceFactory.getCache(config.getCacheType().name());if(ret instanceof CaptchaCacheServiceRedisImpl){((CaptchaCacheServiceRedisImpl)ret).setStringRedisTemplate(redisTemplate);}return ret;}/*** 國際化配置* @return*/
// @Bean
// @ConditionalOnMissingBean
// public MessageSource messageSource() {
// ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
// messageSource.setBasenames("messages/messages","captcha/messages");
// messageSource.setDefaultEncoding("UTF-8");
// return messageSource;
// }
}
實現類
/*** 對于分布式部署的應用,我們建議應用自己實現CaptchaCacheService,比如用Redis,參考service/spring-boot代碼示例。* 如果應用是單點的,也沒有使用redis,那默認使用內存。* 內存緩存只適合單節點部署的應用,否則驗證碼生產與驗證在節點之間信息不同步,導致失敗。** ☆☆☆ SPI: 在resources目錄新建META-INF.services文件夾(兩層),參考當前服務resources。* @Title: 使用redis緩存* @author Devli* @date 2020-05-12*/
public class CaptchaCacheServiceRedisImpl implements CaptchaCacheService {@Overridepublic String type() {return "redis";}private static final String LUA_SCRIPT = "local key = KEYS[1] " +"local incrementValue = tonumber(ARGV[1]) " +"if redis.call('EXISTS', key) == 1 then " +" return redis.call('INCRBY', key, incrementValue) " +"else " +" return incrementValue " +"end";public void setStringRedisTemplate(StringRedisTemplate stringRedisTemplate) {this.stringRedisTemplate = stringRedisTemplate;}private StringRedisTemplate stringRedisTemplate;@Overridepublic void set(String key, String value, long expiresInSeconds) {stringRedisTemplate.opsForValue().set(key, value, expiresInSeconds, TimeUnit.SECONDS);}@Overridepublic boolean exists(String key) {return stringRedisTemplate.hasKey(key);}@Overridepublic void delete(String key) {stringRedisTemplate.delete(key);}@Overridepublic String get(String key) {return stringRedisTemplate.opsForValue().get(key);}@Overridepublic Long increment(String key, long val) {// 執行 Lua 腳本RedisScript<Long> script = new DefaultRedisScript<>(LUA_SCRIPT, Long.class);// 執行 Lua 腳本return stringRedisTemplate.execute(script,Collections.singletonList(key),String.valueOf(val));}@Overridepublic void setExpire(String key, long l) {stringRedisTemplate.expire(key, l, TimeUnit.SECONDS);}
}
動態實現類
resources/META-INF/services/com.anji.captcha.service.CaptchaCacheService
內容:com.captcha.service.CaptchaCacheServiceRedisImpl --實現類的包路徑
Java SPI 機制概述 Java SPI
機制允許開發者為某些接口提供實現,而不需要直接修改應用程序的源代碼。通過這種方式,應用程序能夠在運行時動態地加載接口的實現類。常見的使用場景包括數據庫驅動、日志框架等。
獲取驗證碼
@RestController
@RequiredArgsConstructor
@RequestMapping("/captcha")
public class CaptchaController {private final CaptchaService captchaService;@PostMapping("/getCaptcha")public R get(@RequestBody CaptchaVO data) {return R.success("獲取成功",captchaService.get(data));}//@PostMapping("/check")// public ResponseModel check(@RequestBody CaptchaVO data) {// return captchaService.check(data);// }}
響應參數
{"repCode": "0000","repData": {"originalImageBase64": "底圖base64","point": { //默認不返回的,校驗的就是該坐標信息,允許誤差范圍"x": 205,"y": 5},"jigsawImageBase64": "滑塊圖base64","token": "71dd26999e314f9abb0c635336976635", //一次校驗唯一標識"secretKey": "16位隨機字符串", //aes秘鑰,開關控制,前端根據此值決定是否加密"result": false,"opAdmin": false},"success": true,"error": false
}
請求參數
{"captchaType": "blockPuzzle", //驗證碼類型 clickWord"clientUid": "唯一標識" //客戶端UI組件id,組件初始化時設置一次,UUID(非必傳參數)
}
緩存信息
后端驗證
@PostMapping("/login")
public ResponseModel get(@RequestParam("captchaVerification") String captchaVerification) {CaptchaVO captchaVO = new CaptchaVO();captchaVO.setCaptchaVerification(captchaVerification);ResponseModel response = captchaService.verification(captchaVO);if(response.isSuccess() == false){//驗證碼校驗失敗,返回信息告訴前端//repCode 0000 無異常,代表成功//repCode 9999 服務器內部異常//repCode 0011 參數不能為空//repCode 6110 驗證碼已失效,請重新獲取//repCode 6111 驗證失敗//repCode 6112 獲取驗證碼失敗,請聯系管理員}return response;
}
前端請求
{"captchaType": "blockPuzzle","pointJson": "QxIVdlJoWUi04iM+65hTow==", //aes加密坐標信息"token": "71dd26999e314f9abb0c635336976635" //get請求返回的token
}
自定義驗證碼
配置文件開啟
aj:captcha:# 滑動驗證底圖路徑,不配置將使用默認圖片jigsaw: classpath:images/jigsaw
路徑格式
images/jigsaw
- original 背景圖
- slidingBlock 驗證碼塊