介紹
一個基於Spring boot 2.4.2、JDK 1.8、Security、防惡意請求技術實現的前後端分離的腳手架,可以爲開發人員省去前期框架調研和搭建的成本。源碼在碼雲上。
軟件架構
- Spring boot 2.4.2
- JDK 1.8
- Security
- kk-anti-reptile(反爬蟲接口防刷組件)
- Redis(登錄用戶信息)
- MySQL
- MyBatis
安裝教程
- 克隆 本代碼到本地
- 修改application.yml配置,包含Mysql數據庫信息、Redis連接信息、kk-anti-reptile配置信息(不修改也可以,默認,詳細參數見:kk-anti-reptile)
- 將項目other/SQL/中的腳本放到mysql中執行,初始化表結構
- 啓動項目
- 使用測試工具或者前端連接請求
使用說明
本示例在TestWebSecurity
類中配置了Security前端登錄接口和退出登錄接口,如想自定義接口,請修改如下圖圈中的配置
application.yml
配置文件中kk-anti-reptile
部分配置如下:
# 惡意請求
anti:
reptile:
manager:
# 激活惡意請求/反爬蟲配置
enabled: true
# 需要攔截的請求,多個以“,”分隔,或者直接在controller方法上添加@AntiReptile
# include-urls: ^/admin/.*$
ua-rule:
#允許linux系統訪問
allowed-linux: true
# 全局攔截,默認爲false,爲false時,需要配置上面的include-urls
global-filter-mode: true
詳細參數請參見kk-anti-reptile
請求示例
登錄接口
請求鏈接
http://localhost:8099/auth/login
請求參數
username:admin password:1234
注意,此處需要使用表單提交,postman中如下:
響應參數
登錄成功返回參數如下:
{
"code": "00000",
"msg": "操作成功!",
"data": {
"token": "3aa72e4a-74b5-4542-9e56-e7f31ec5ce09",
"permissions": [],
"loginTime": 1611284216123
}
}
其中,token的值就是前端需要在每次請求中在請求頭部傳遞到後端的參數
退出登錄接口
請求鏈接
http://localhost:8099/auth/logout
請求參數
請求頭部需要放置如下參數:
X-token:token的值
Postman中如下:
響應參數
{
"code": "00000",
"msg": "您已經退出登錄!"
}
正常接口
正常業務邏輯中調用的接口傳參
請求鏈接
http://localhost:8099/test/listOrientations
請求參數
header中必須帶有X-token參數,其他業務參數請寫在請求體中
Postman中如下:
正常響應參數(沒有超過反爬蟲預警)
{
"code": "00000",
"msg": "ddd"
}
被攔截的響應參數
當使用postman多次請求,請求超過閾值,將會返回驗證碼頁面(如果前端JQ請求,請參照kk-anti-reptile處理方式正常顯示驗證碼)
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>kk-anti-reptile驗證</title>
<script>
function getXhr() {
var xhr = null;
try {
xhr = new XMLHttpRequest();
} catch (e) {
try {
xhr = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
}
return xhr;
}
function refresh() {
var xhr = getXhr();
var verifyId = document.getElementById("verifyId").value;
var baseUrl = document.getElementById("baseUrl").value;
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
var verifyObj = JSON.parse(xhr.responseText);
document.getElementById("verifyId").value = verifyObj.verifyId;
document.getElementById("verifyImg").src = verifyObj.verifyImgStr;
}
}
xhr.open("POST", baseUrl + "/kk-anti-reptile/refresh?verifyId="+verifyId, "true");
xhr.send();
}
function validate() {
var elements = document.getElementById("verifyFrom");
var formData = new FormData();
for(var i = 0; i < elements.length; i++) {
formData.append(elements[i].name, elements[i].value);
}
var baseUrl = document.getElementById("baseUrl").value;
var xhr = getXhr();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
var obj = JSON.parse(xhr.responseText);
if (obj.result == true) {
closeThisWindows();
} else {
alert("驗證碼填寫錯誤")
}
}
}
xhr.open("POST", baseUrl + "/kk-anti-reptile/validate", "true");
xhr.send(formData);
}
function closeThisWindows() {
if (navigator.userAgent.indexOf("MSIE") > 0) {
if (navigator.userAgent.indexOf("MSIE 6.0") > 0) {
window.opener = null;
window.close();
} else {
window.open('', '_top');
window.top.close();
}
} else if (navigator.userAgent.indexOf("Firefox") > 0) {
window.location.href = 'about:blank';
} else if (navigator.userAgent.indexOf("AppleWebKit") > 0) {
window.location.href = 'about:blank';
window.close();
} else {
window.opener = null;
window.open('', '_self', '');
window.close();
}
}
</script>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
<title>普通驗證碼</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
form {
width: 240px;
margin: 100px auto;
padding: 20px;
}
input[type="text"] {
margin: 10px 0;
padding: 0 4px;
width: 100%;
height: 32px;
border: 1px solid #c3c3c3;
border-radius: 4px;
}
input[type="button"] {
width: 100%;
height: 32px;
color: #fff;
background-color: #40a9ff;
border-color: #40a9ff;
border-radius: 4px;
outline: 0;
cursor: pointer;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.12);
box-shadow: 0 2px 0 rgba(0, 0, 0, 0.045);
border-style: none;
}
.img-wrapper {
display: flex;
align-items: center;
}
.img-wrapper img {
width: 130px;
height: 48px;
}
.img-wrapper a {
text-decoration: none;
color: #1890ff;
}
</style>
<form id="verifyFrom" method="post" action="">
<input type="hidden" id="baseUrl" name="baseUrl">
<input type="hidden" id="verifyId" name="verifyId" value="d4eee0b1-b416-4231-96d8-8af6f70ad2c2">
<input type="hidden" id="realRequestUri" name="realRequestUri" value="/test/listOrientations">
<span>操作頻繁,請輸入驗證碼</span>
<div class="img-wrapper">
<img id="verifyImg" src="data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgAAAIIAAAAwCAIAAABSYzXUAAAKmUlEQVR42u2cC2yVZxnHmzQ6x8RpYtTMazSOLZuJi9FhZowa57zh3HQumXPOazRTzOKVBadGwrpCy4QxLmVcymUUaMso13Ir0FLAstJyWcu1W2GspbVc1q2FwuPvOe/hO5fv9p7Tc2iTnSdfTsg53/d+7/tc/s//ed635ElOhoHk5VSQM0NOcmZwyRsXpaNXP3NmGALVVx2Rf9XKDyvlu8uj173lMq5Glh6SM705M2RfKlrlwZV6leyT2nY53K3RcKxH9rwm85vloVVqj6kNcq4v5ZEvX5G+gZwZLIKACLi/Qpa3SL+PvgYuq21+vkZ+UiXNnb5DvXVJTpyV+lNq1Odekr9vl1+tU/stOZgzQ6D87y0Zu1Gv1y6E34yWiRUga0ubnO2Tl7tk6yvywiEp3iN/3qIWMjj2QKUOOHGnzGuWdcek8XXp6cuZIVCtj29WlfGPAEh5/Q1VJQqd26TK/X653PSsjC5VjaN6DIAZMAYmaelW8+RyQ2oys1H1SEAEQwrqRvX8+8kd+n1lq0ysl7uXBqFTzgxWgs/ivHctUs2GQgrRQEwkSeEuTRUBYZQzQxCk/L5aFY26b58jt5akDynwV2jV2mM5M9ixFDek7DolrV1qDDLtYARm9egaJVFvUzOkxFI8IWVTWwY0CNMlIBpOvw3MANXzhJRBspSn6qVoTwamR8FBnh96M1AfXrqcRTMsPugBKW1nU6tL3cKAYFcaRcakXfL1F2RkkeQXyPWT5FMzNcccPDPUZkBNY5bLT1fLn7YoeQAKVh/VBgAwnVJfDNyY3yw/qJAP/Efe8bRcVyifnim/XKtDuSFl8FmEnEGQpSR4wI3FkveU95VB1mRlhnN9UrRbPeKGyaqvEZNl9AJ5rFoW7pdpDeqzv1mv2jS48aOV+hORiyOT0La9Koe65MybyZoFXkfN8l3hHzZm2AwdvTo3m7LZkaWHfKfnXF9ZfK3MAEZ/aKr3JD7xnKZNR873y9Ee5S2rjsicJsXixzfJw6tkzIpo2xL3+VuNAvQT2+SdhZFBCnxX+Nv1mTdDh3XHFIOBQmYmd8yVZS9L78VoBKOQjzwbmycOmnUzVB0JcQfwpDNsbf0DcuqC7OuQjScU0CbUyYhJ0cffO0UXeX+FUh0CiCC4ZXbkp4n6Wdc+ZNHw163RGX6rLDmOj/XoUOOu3vCZOVk2A7TvfVOiL7t1tgapaUYyD2eWXLh8SoKuowsokdMXpLVbG5kkz1mN8u86tceHr/raR6drXn2iRqbsUftVn1Bwx6L9A1nPDZ+cEZ0D00sSBsEMkBRzAyidXTM4uv7cPLnQn7AknAv+YH4lQlNSx3WF0Qf9yAZAF42VYkWA0v2KY6AZmGZKM1AOrPtdtYLbtL3y4mHZeVLxMHhjID2m5BaqaIbiXWaS738my2ZA+/kR7GaR8DYAavz22C7Vd5ZF55H/dAqYC8iap+4rT2e6VyIdBQZ5ZLXcuUAB4eZZCmtfWiTfXqazginAFyin4Q6E7+Y22d+pYY3zZrZueGxDJnNYXiin3Htapu9V+KYELdmnzKf9vOod7zPzeFehOin32OxSMWnzFDpKQ4AjVIm6n2/S2o1pEFLgFZXtz9Yo+4LsrjmqHBomTaEHqx4TcRo+v1Emtz8vBfXpM2zkeE/U/GYVN00LT40ZMAM4yArxL+A7qQ3gKBSsYElgOoECTQoWJ4YMIoE/uBVADMJSGRF//9whXW8GVcIU0i3dHpR6XI1uW1LlJQlxgLWIifXH5YulMrY6TYZN+DJJpXYFUQYBW331XPYJK6rHzQnA+CIFfwSL4Q9Gm7A6MrZEtgy5k1VtOB70Pof7op3x27zZF7wAj3bLljadj19GYWKoEoUGBOXUBt3zSYNhlx6IzHxiwjzvXaHlfXbNQBwwD6rceHdws9Xa9uQGJAsIiInrr1JVECOYClcmplPMjFIWHgjJ/5gBXfsJcMqi8PeUGPYz/1W2NrJY3lOsVHtkYl1N2b+jXVq6NH1euZJRM+BQYFFSA4tiLf71FNWe6GF2bv1cMj+uXoMysTy824Q/oy06oMzY/HpjcQLsNndqfgqFchPBAQdbknbfUmpxMzLwC4WFI3x2bmwhYIPBt/vKrRj2QAQn47/0NgP5FvSMxyI0le+qeLnNLbyDPOH5U7wZQB5PFg8zdixBnnCEhcHTQoW3owhUFhAxoXvRbtkUwcNNiXsV9yyNzvORKh2NPAGdCWDYIB533l0md5bKXQvla0uUQWAt7JHn2VPE72rbvYlTzSux13N53obL8HpPFuuA0oyXfNdc3hK95wvzY1/iFisPW6kMEhWfADwXmN7JjCRp6ojxpWCGTc6n2iCXwEHQzI+r9POri+WOefLxGTJqtpcZqA9Ct0ceqIzOAObjKTiCp0s6Kbr3YhA0m3uwmSN4hmUNbJwgeP6ZOqdkWUhjS2J0Ql0CGDIHGHPdyUiZ7H4G5of9gwV8dGsqXsjtf9wcRFhDUlbi8pj9PWXS2GGF6eRhcMDm3CNFNW7ueWoPLuCc2vN7qae7eApFzF+2BnmGhxmYWa1FTy3YEVgJvuYW8NE8GN+adacHhw0zDk6EOj44Vc+noF+GJUlAxgJYln0z1Zxh/ccOHTb+DOuIySEdF4QcYO758qKQ2guVBgNgnjt8bDqRJ8+HwKLpaLqJDQhrHqRq85O5TdF7bp6tGgE9qFRIaEQD1RkuQgJEawFNcstocJvEOdH96OroULzXr+/pAOy0hqBhSVTxvN/KDEZ9777aakfdngInMzdAAFLt739sevRZ3NAt0FaHGX9vRcwhknIDQBFghtDcECpU3Q6pwxLwHyeF4ArwQGom8+ttJUF7hdxsE5re0eAUyZ747jAZP6YUEA3IkoNXe4IF8uT2GDqhWeLAsQG+Fq9KT6YEpmMeU8bbMyVLQdehu2+AQdLb3Vt4Yy12Er1zQ9HuhF2w/Z1RtgpF+/W62E8PvRhEVzxzgxGnPel3Udk1Jh5CKfKpGyZEtigcg4XWDSkJHuPsuLgvCthQ9GZ6Nk1MX6bkUFK/a/SChE0IS6YUU+vu2MZD0nVDkdafSeJXRZMD+B6rW1bRqcq5Pq0cgQdzMoM5j5qlLJb6yUYguzYH1Hzrhr5L2i3xswHVYIANAuqGeKHsHL9NzQnhY4Wsk9WSDwrqvVm8X08J9CCN2/SUrrEwZ5DZptwJqaIbTqsxsD/ElIvsigF2nrQqoDrScskA9/HrsDJVnrLpsF5jOWO9AW7bU0rJBciQfj2lYMEDmLd7zyB4v4H7v1mmFYnnfsMQiv1xkBQ6rJYS3GEd5Lzjd9+gKGb3bUajniJ4uCrN+Bu+0eC532DZDebFtekebAmNBgf0YE2mecn1i7Xy+fl6yGO4ickNNn+Zkhfa3SUmbA6k8ErigLda9kEDcoOlFU3RS9jVn1I4Gp7CckJ3mWQwe9FJ7mm5Fx0q0OVUqQ6OwlPDU2ANNkVM+OFJ3C3+ZAb2AOxwQy54FAzSbG5YnswIFXwHc9ofmIBHcL+Nxw2JoB8bF7E90W3OKTFi/F/TYxtqNKrEDOZGAJBAtj8+U9GqiNQ/MEzNAIPAR0O9Kp2D9ebUXvb+b4kNx9XYh7vD74Qscadni3D4CCgS+udy/wfo2vAEEaPingAAAABJRU5ErkJggg==">
<a href="javascript:void(0);" onclick="refresh()">刷新</a>
</div>
<input type="text" id="result" name="result">
<br>
<input type="button" value="確認" onclick="validate()">
</form>
讚賞我
- 如果您覺得這個不錯,可以打賞下作者,您的贊同是作者不懈努力的源泉