AJ-Captcha:輕松集成圖形驗(yàn)證碼
引言
隨著互聯(lián)網(wǎng)的快速發(fā)展,各種在線服務(wù)和應(yīng)用變得越來越普及,同時也帶來了大量的自動化攻擊和濫用行為。為了保護(hù)網(wǎng)站和服務(wù)免受惡意機(jī)器人的侵?jǐn)_,驗(yàn)證碼(Captcha)技術(shù)應(yīng)運(yùn)而生。AJ-Captcha 是一種高效、安全且易于集成的驗(yàn)證碼解決方案,本文將詳細(xì)介紹AJ-Captcha 的技術(shù)原理、實(shí)現(xiàn)方式及其應(yīng)用場景。
應(yīng)用場景
- 注冊登錄保護(hù):在用戶注冊賬號或登錄已有賬戶時啟用AJ-Captcha,可以有效阻止惡意注冊和暴力破解嘗試。
- 表單提交防護(hù):對于那些容易受到大量垃圾信息騷擾的在線表格(如反饋建議、活動報名等),添加AJ-Captcha能顯著降低無效數(shù)據(jù)量。
- 支付確認(rèn)環(huán)節(jié):在涉及資金交易的關(guān)鍵步驟加入額外的身份驗(yàn)證措施,確保每筆訂單都出自合法用戶之手。
- 資源下載限制:對于一些珍貴資料或者受版權(quán)保護(hù)的內(nèi)容,可以通過設(shè)置AJ-Captcha作為下載前的最后一道防線,防止未經(jīng)授權(quán)的批量抓取。
具體實(shí)現(xiàn)
1.依賴引入
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- captcha 圖形驗(yàn)證碼-->
<dependency>
<groupId>com.anji-plus</groupId>
<artifactId>spring-boot-starter-captcha</artifactId>
<version>1.3.0</version>
</dependency>
2.配置yml
server:
port: 10001
# 數(shù)據(jù)庫配置
spring:
datasource:
driver-class-name: com.kingbase8.Driver
url: jdbc:kingbase8://localhost:54321/test?currentSchema=public
username: system
password: root
redis:
host: localhost
password: yianweilai
port: 6379
# Anji-plus 驗(yàn)證碼配置
aj:
captcha:
# 緩存類型
cache-type: redis
# blockPuzzle 滑塊 clickWord 文字點(diǎn)選 default默認(rèn)兩者都實(shí)例化
type: clickWord
# 校驗(yàn)滑動拼圖允許誤差偏移量(默認(rèn)5像素)
slip-offset: 5
# aes加密坐標(biāo)開啟或者禁用(true|false)
aes-status: true
# 滑動干擾項(0/1/2)
interference-options: 0
# 右下角水印
water-mark: "一安未來"
3.配置Redis和Captcha
@Configuration
public class RedisConfig {
@Resource
private RedisConnectionFactory factory;
@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(factory);
GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(stringRedisSerializer);
redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);
redisTemplate.setHashKeySerializer(stringRedisSerializer);
redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
@Service
public class CaptchaCacheServiceRedis implements CaptchaCacheService {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Override
public String type() {
return "redis";
}
@Override
public void set(String key, String value, long expiresInSeconds) {
stringRedisTemplate.opsForValue().set(key, value, expiresInSeconds, TimeUnit.SECONDS);
}
@Override
public boolean exists(String key) {
return stringRedisTemplate.hasKey(key);
}
@Override
public void delete(String key) {
stringRedisTemplate.delete(key);
}
@Override
public String get(String key) {
return stringRedisTemplate.opsForValue().get(key);
}
}
4.加載服務(wù)實(shí)現(xiàn)
在 resources 目錄下新建 META-INF/services,在 services 目錄下新建 com.anji.captcha.service.CaptchaCacheService 的文件,內(nèi)容指向 CaptchaCacheService 的配置路徑。
5.編寫首頁
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>驗(yàn)證碼示例</title>
<link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="/css/verify.css">
<script src="/js/jquery.min.js"></script>
<script src="/js/crypto-js.js"></script>
<script src="/js/ase.js"></script>
<script src="/js/verify.js"></script>
<style>
body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
}
.container {
margin-top: -80px;
width: 78%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
border-radius: 10px;
border: 1px solid gray;
padding: 25px;
}
form {
width: 80%;
}
.btn {
border: none;
outline: none;
width: 300px;
height: 40px;
line-height: 40px;
text-align: center;
cursor: pointer;
background-color: #409EFF;
color: #fff;
font-size: 16px;
letter-spacing: 1em;
}
</style>
</head>
<body>
<div class="container">
<h2>請登錄</h2>
<form th:action="@{/login}" method="post">
<div class="form-group">
<label for="username">用戶名</label>
<input type="text" class="form-control" id="username" name="username" />
</div>
<div class="form-group">
<label for="password">密碼</label>
<input type="password" class="form-control" id="password" name="password" />
</div>
<div class="form-group">
<button class="btn btn-primary" id='btn' type="button" >登錄</button>
<div id="mpanel" style="margin-top:50px;"></div>
<div id="tip" style="margin-top:50px;"></div>
</div>
</form>
</div>
<script>
//slideVerify 對應(yīng)blockPuzzle模式
//pointsVerify 對應(yīng)clickWord模式
$('#mpanel').pointsVerify({
baseUrl: 'http://localhost:10001',
mode: 'pop',
containerId: 'btn',//pop模式 必填 被點(diǎn)擊之后出現(xiàn)行為驗(yàn)證碼的元素id
imgSize: {
width: '400px',
height: '200px'
},
barSize: {
width: '400px',
height: '40px'
},
beforeCheck: function () {
var name = $("#username").val();
var pass = $('#password').val();
if (name === '' || pass === '') {
$("#tip").html('<div class="alert alert-danger">請輸入用戶名和密碼!</div>');
setTimeout(function() {
$("#tip div.alert").fadeOut(500);
}, 5000);
return false;
}
return true;
},
ready: function () {},
success: function (params) {
var name = $("#username").val();
var pass = $('#password').val();
$.ajax({
type: "POST",
url: "/login",
data: {
username: name,
password: pass
},
success: function (response) {
if (response.success) {
$("#tip").html('<div class="alert alert-success">登錄成功</div>');
} else {
$("#tip").html('<div class="alert alert-danger">登錄失敗</div>');
}
setTimeout(function() {
$("#tip div.alert").fadeOut(500);
}, 5000);
},
error: function () {
$("#tip").html('<div class="alert alert-danger">登錄請求出錯</div>');
setTimeout(function() {
$("#tip div.alert").fadeOut(500);
}, 5000);
}
});
},
error: function () {}
});
</script>
</body>
</html>