国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - 編程技術 - 滑動驗證碼的設計與理解

滑動驗證碼的設計與理解

2020-09-22 16:03半天想不出昵稱的斌 編程技術

這篇文章主要介紹了滑動驗證碼的設計與理解,本文通過實例代碼給大家介紹小網站是怎么設計的,代碼簡單易懂,需要的朋友可以參考下

在介紹之前,首先一個概念明確一個共識:沒有攻不破的網站,只有值不值得。

這意思是說,我們可以盡可能的提高自己網站的安全,但并沒有絕對的安全,當網站安全級別大于攻擊者能得到的回報時,你的網站就是安全的。

所以百度搜到的很多驗證碼都已經結合了人工智能分析用戶行為,很厲害。但這里只介紹我的小網站是怎么設計的。

大概邏輯:當需要驗證碼時,前端發送ajax向后臺請求相關數據發送回前端,由前端生成(與后端生成圖片,然后傳送圖片到前端的做法相比安全性要差很多。但也是可以預防的,后端可以對此Session進行請求記錄,如果在一定時間內惡意多次請求,可以進行封禁ip等對策),驗證完成后,后臺再對傳回的數據進行校驗。

效果圖:

滑動驗證碼的設計與理解

滑動驗證碼的設計與理解

1|0js類的設計:

 

1.定義一個驗證碼父類,因為目前只有這一個驗證類型,倘若以后再要擴展其他驗證類型呢。那么它們之間肯定有很多公共之處(如:驗證成功、失敗的回調,獲取驗證碼的類型,獲取驗證結果等),所以這些共同點可以提煉出來,下面是我目前的父類樣子:

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
/**
* 驗證碼的父類,所有驗證碼都要繼承這個類
* @param id 驗證碼的唯一標識
* @param type 驗證碼的類型
* @param contentDiv 包含著驗證碼的DIV
* @constructor
*/
var Identifying = function (id,type,contentDiv){
 this.id = id;
 this.type = type;
 this.contentDiv=contentDiv;
}
/**
* 銷毀函數
*/
Identifying.prototype.destroy = function(){
 this.successFunc = null;
 this.errorFunc = null;
 this.clearDom();
 this.contentDiv = null;
}
/**
* 清除節點內容
*/
Identifying.prototype.clearDom = function(){
 if(this.contentDiv instanceof jQuery){
  this.contentDiv.empty();
 }else if(this.contentDiv instanceof HTMLElement){
  this.contentDiv.innerText = "";
 }
}
/**
* 回調函數
* 驗證成功后進行調用
* this需要指具體驗證類
* @param result 對象,有對應驗證類的傳遞的參數,具體要看驗證類
*/
Identifying.prototype.success = function (result) {
 if(this.successFunc instanceof Function){
  this.successFunc(result);
 }
}
/**
* 驗證失敗發生錯誤調用的函數
* @param result
*/
Identifying.prototype.error = function (result) {
 if(this.errorFunc instanceof Function){
  this.errorFunc(result);
 }else{
  //統一處理錯誤
 }
}
/**
* 獲取驗證碼id
*/
Identifying.prototype.getId = function () {
 return this.id;
}
/**
* 獲取驗證碼類型
* @returns {*}
*/
Identifying.prototype.getType = function () {
 return this.type;
}
/**
* 顯示驗證框
*/
Identifying.prototype.showIdentifying = function(callback){
 this.contentDiv.show(null,callback);
}
/**
* 隱藏驗證框
*/
Identifying.prototype.hiddenIdentifying = function(callback){
 this.contentDiv.hide(null,callback);
}
/**
* 獲得驗證碼顯示的dom元素
*/
Identifying.prototype.getContentDiv = function () {
 return this.contentDiv;
}

然后,滑動驗證碼類繼承此父類(js繼承會單獨寫篇文章),滑動驗證碼類如下:

  

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
/**
* 滑動驗證類
* complete傳遞的參數為identifyingId,identifyingType,moveEnd_X
* @param config 各種配置
*/
var ImgIdentifying = function(config) {
 Identifying.call(this, config.identifyingId, config.identifyingType,config.el);
 this.config = config;
 this.init();
 this.showIdentifying();
}
//繼承父類
extendClass(Identifying, ImgIdentifying);
/**
* 銷毀函數
*/
ImgIdentifying.prototype.destroy = function () {
 Identifying.prototype.destroy.call(this);
}
var width = '260';
var height = '116';
var pl_size = 48;
var padding_ = 20;
ImgIdentifying.prototype.init = function () {
 this.clearDom();
 var el = this.getContentDiv();
 var w = width;
 var h = height;
 var PL_Size = pl_size;
 var padding = padding_;
 var self = this;
 //這個要轉移到后臺
 function RandomNum(Min, Max) {
  var Range = Max - Min;
  var Rand = Math.random();
  if (Math.round(Rand * Range) == 0) {
   return Min + 1;
  } else if (Math.round(Rand * Max) == Max) {
   return Max - 1;
  } else {
   var num = Min + Math.round(Rand * Range) - 1;
   return num;
  }
 }
 //確定圖片
 var imgSrc = this.config.img;
 var X = this.config.X;
 var Y = this.config.Y;
 var left_Num = -X + 10;
 var html = '<div style="position:relative;padding:16px 16px 28px;border:1px solid #ddd;background:#f2ece1;border-radius:16px;">';
 html += '<div style="position:relative;overflow:hidden;width:' + w + 'px;">';
 html += '<div style="position:relative;width:' + w + 'px;height:' + h + 'px;">';
 html += '<img id="scream" src="' + imgSrc + '" style="width:' + w + 'px;height:' + h + 'px;">';
 html += '<canvas id="puzzleBox" width="' + w + '" height="' + h + '" style="position:absolute;left:0;top:0;z-index:222;"></canvas>';
 html += '</div>';
 html += '<div class="puzzle-lost-box" style="position:absolute;width:' + w + 'px;height:' + h + 'px;top:0;left:' + left_Num + 'px;z-index:11111;">';
 html += '<canvas id="puzzleShadow" width="' + w + '" height="' + h + '" style="position:absolute;left:0;top:0;z-index:222;"></canvas>';
 html += '<canvas id="puzzleLost" width="' + w + '" height="' + h + '" style="position:absolute;left:0;top:0;z-index:333;"></canvas>';
 html += '</div>';
 html += '<p class="ver-tips"></p>';
 html += '</div>';
 html += '<div class="re-btn"><a></a></div>';
 html += '</div>';
 html += '<br>';
 html += '<div style="position:relative;width:' + w + 'px;margin:auto;">';
 html += '<div style="border:1px solid #c3c3c3;border-radius:24px;background:#ece4dd;box-shadow:0 1px 1px rgba(12,10,10,0.2) inset;">';//inset 為內陰影
 html += '<p style="font-size:12px;color: #486c80;line-height:28px;margin:0;text-align:right;padding-right:22px;">按住左邊滑塊,拖動完成上方拼圖</p>';
 html += '</div>';
 html += '<div class="slider-btn"></div>';
 html += '</div>';
 el.html(html);
 var d = PL_Size / 3;
 var c = document.getElementById("puzzleBox");
 //getContext獲取該dom節點的canvas畫布元素
 //---------------------------------這一塊是圖片中央缺失的那一塊--------------------------------------
 var ctx = c.getContext("2d");
 ctx.globalCompositeOperation = "xor";
 //設置陰影模糊級別
 ctx.shadowBlur = 10;
 //設置陰影的顏色
 ctx.shadowColor = "#fff";
 //設置陰影距離的水平距離
 ctx.shadowOffsetX = 3;
 //設置陰影距離的垂直距離
 ctx.shadowOffsetY = 3;
 //rgba第四個參數是透明度,前三個是三原色,跟rgb比就是多了第四個參數
 ctx.fillStyle = "rgba(0,0,0,0.8)";
 //beginPath() 方法開始一條路徑,或重置當前的路徑。
 //提示:請使用這些方法來創建路徑:moveTo()、lineTo()、quadricCurveTo()、bezierCurveTo()、arcTo() 以及 arc()。
 ctx.beginPath();
 //指線條的寬度
 ctx.lineWidth = "1";
 //strokeStyle 屬性設置或返回用于筆觸的顏色、漸變或模式
 ctx.strokeStyle = "rgba(0,0,0,0)";
 //表示畫筆移到(X,Y)位置,沒畫東西
 ctx.moveTo(X, Y);
 //畫筆才開始移動到指定坐標,之間畫一條直線
 ctx.lineTo(X + d, Y);
 //繪制一條貝塞爾曲線,一共四個點確定,開始點(沒在參數里),和兩個控制點(1和2參數結合,3和4參數結合),結束點(5和6參數結合)
 ctx.bezierCurveTo(X + d, Y - d, X + 2 * d, Y - d, X + 2 * d, Y);
 ctx.lineTo(X + 3 * d, Y);
 ctx.lineTo(X + 3 * d, Y + d);
 ctx.bezierCurveTo(X + 2 * d, Y + d, X + 2 * d, Y + 2 * d, X + 3 * d, Y + 2 * d);
 ctx.lineTo(X + 3 * d, Y + 3 * d);
 ctx.lineTo(X, Y + 3 * d);
 //必須和beginPath()成對出現
 ctx.closePath();
 //進行繪制
 ctx.stroke();
 //根據fillStyle進行填充
 ctx.fill();
 //---------------------------------這個為要移動的塊------------------------------------------------
 var c_l = document.getElementById("puzzleLost");
 //---------------------------------這個為要移動的塊增加陰影------------------------------------------------
 var c_s = document.getElementById("puzzleShadow");
 var ctx_l = c_l.getContext("2d");
 var ctx_s = c_s.getContext("2d");
 var img = new Image();
 img.src = imgSrc;
 img.onload = function () {
  //從原圖片,進行設置處理再顯示出來(其實就是設置你想顯示圖片的位置2和3參數,和框w高h)
  ctx_l.drawImage(img, 0, 0, w, h);
 }
 ctx_l.beginPath();
 ctx_l.strokeStyle = "rgba(0,0,0,0)";
 ctx_l.moveTo(X, Y);
 ctx_l.lineTo(X + d, Y);
 ctx_l.bezierCurveTo(X + d, Y - d, X + 2 * d, Y - d, X + 2 * d, Y);
 ctx_l.lineTo(X + 3 * d, Y);
 ctx_l.lineTo(X + 3 * d, Y + d);
 ctx_l.bezierCurveTo(X + 2 * d, Y + d, X + 2 * d, Y + 2 * d, X + 3 * d, Y + 2 * d);
 ctx_l.lineTo(X + 3 * d, Y + 3 * d);
 ctx_l.lineTo(X, Y + 3 * d);
 ctx_l.closePath();
 ctx_l.stroke();
 //帶陰影,數字越高陰影越嚴重
 ctx_l.shadowBlur = 10;
 //陰影的顏色
 ctx_l.shadowColor = "black";
 // ctx_l.fill(); 其實加這句就能有陰影效果了,不知道為什么加多個圖層
 //分割畫布的塊
 ctx_l.clip();
 ctx_s.beginPath();
 ctx_s.lineWidth = "1";
 ctx_s.strokeStyle = "rgba(0,0,0,0)";
 ctx_s.moveTo(X, Y);
 ctx_s.lineTo(X + d, Y);
 ctx_s.bezierCurveTo(X + d, Y - d, X + 2 * d, Y - d, X + 2 * d, Y);
 ctx_s.lineTo(X + 3 * d, Y);
 ctx_s.lineTo(X + 3 * d, Y + d);
 ctx_s.bezierCurveTo(X + 2 * d, Y + d, X + 2 * d, Y + 2 * d, X + 3 * d, Y + 2 * d);
 ctx_s.lineTo(X + 3 * d, Y + 3 * d);
 ctx_s.lineTo(X, Y + 3 * d);
 ctx_s.closePath();
 ctx_s.stroke();
 ctx_s.shadowBlur = 20;
 ctx_s.shadowColor = "black";
 ctx_s.fill();
 //開始時間
 var beginTime;
 //結束時間
 var endTime;
 var moveStart = '';
 $(".slider-btn").mousedown(function (e) {
  $(this).css({"background-position": "0 -216px"});
  moveStart = e.pageX;
  beginTime = new Date().valueOf();
 });
 onmousemove = function (e) {
  var e = e || window.event;
  var moveX = e.pageX;
  var d = moveX - moveStart;
  if (moveStart == '') {
  } else {
   if (d < 0 || d > (w - padding - PL_Size)) {
   } else {
    $(".slider-btn").css({"left": d + 'px', "transition": "inherit"});
    $("#puzzleLost").css({"left": d + 'px', "transition": "inherit"});
    $("#puzzleShadow").css({"left": d + 'px', "transition": "inherit"});
   }
  }
 };
 onmouseup = function (e) {
  var e = e || window.event;
  var moveEnd_X = e.pageX - moveStart;
  var ver_Num = X - 10;
  var deviation = self.config.deviation;
  var Min_left = ver_Num - deviation;
  var Max_left = ver_Num + deviation;
  if (moveStart == '') {
  } else {
   endTime = new Date().valueOf();
   if (Max_left > moveEnd_X && moveEnd_X > Min_left) {
    $(".ver-tips").html('<i style="background-position:-4px -1207px;"></i><span style="color:#42ca6b;">驗證通過</span><span></span>');
    $(".ver-tips").addClass("slider-tips");
    $(".puzzle-lost-box").addClass("hidden");
    $("#puzzleBox").addClass("hidden");
    setTimeout(function () {
     $(".ver-tips").removeClass("slider-tips");
    }, 2000);
    self.success({
     'identifyingId': self.config.identifyingId, 'identifyingType': self.config.identifyingType,
     'moveEnd_X': moveEnd_X
    })
   } else {
    $(".ver-tips").html('<i style="background-position:-4px -1229px;"></i><span style="color:red;">驗證失敗:</span><span style="margin-left:4px;">拖動滑塊將懸浮圖像正確拼合</span>');
    $(".ver-tips").addClass("slider-tips");
    setTimeout(function () {
     $(".ver-tips").removeClass("slider-tips");
    }, 2000);
    self.error();
   }
  }
  //0.5指動畫執行到結束一共經歷的時間
  setTimeout(function () {
   $(".slider-btn").css({"left": '0', "transition": "left 0.5s"});
   $("#puzzleLost").css({"left": '0', "transition": "left 0.5s"});
   $("#puzzleShadow").css({"left": '0', "transition": "left 0.5s"});
  }, 1000);
  $(".slider-btn").css({"background-position": "0 -84px"});
  moveStart = '';
  $(".re-btn a").on("click", function () {
   Access.getAccess().initIdentifying($('#acessIdentifyingContent'));
  })
 }
}
/**
* 獲取該類型驗證碼的一些參數
*/
ImgIdentifying.getParamMap = function () {
 var min_X = padding_ + pl_size;
 var max_X = width - padding_ - pl_size - pl_size / 6;
 var max_Y = padding_;
 var min_Y = height - padding_ - pl_size - pl_size / 6;
 var paramMap = new Map();
 paramMap.set("min_X", min_X);
 paramMap.set("max_X", max_X);
 paramMap.set("min_Y", min_Y);
 paramMap.set("max_Y", max_Y);
 return paramMap;
}
/**
* 設置驗證成功的回調函數
* @param success
*/
ImgIdentifying.prototype.setSuccess = function (successFunc) {
 this.successFunc = successFunc;
}
/**
* 設置驗證失敗的回調函數
* @param success
*/
ImgIdentifying.prototype.setError = function (errorFunc) {
 this.errorFunc = errorFunc;
}

其中init的方法,大家就可以抄啦,驗證碼是這里生成的(感謝網上一些熱心網友提供的Mod,在此基礎上改的)。

2|0后端的設計:

 

首先要有一個驗證碼的接口,將一些常量和共同的方法抽象到接口中(接口最重要的作用就是行為的統一,意思是我如果知道這個是驗證碼,那么必定就會有驗證的方法,不管它是滑動驗證,圖形驗證等,然后就可以放心的調用驗證方法去獲取驗證結果,下面過濾器設計就可以立馬看到這作用。具體java接口的說明會單獨寫篇文章),接口如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/**
* 驗證碼類的接口,所有驗證碼必須繼承此接口
*/
public interface I_Identifying<T> {
 String EXCEPTION_CODE = SystemStaticValue.IDENTIFYING_EXCEPTION_CODE;
 String IDENTIFYING = "Identifying";
 //--------------以下為驗證碼大體錯誤類型,拋出錯誤時候用,會傳至前端---------------
 //驗證成功
 String SUCCESS = "Success";
 //驗證失敗
 String FAILURE = "Failure";
 //驗證碼過期
 String OVERDUE = "Overdue";
 //-------以下為驗證碼具體錯誤類型,存放在checkResult-------------
 String PARAM_ERROR = "驗證碼參數錯誤";
 String OVERDUE_ERROR = "驗證碼過期";
 String TYPE_ERROR = "驗證碼業務類型錯誤";
 String ID_ERROR = "驗證碼id異常";
 String CHECK_ERROR = "驗證碼驗證異常";
 /**
 * 獲取生成好的驗證碼
 * @param request
 * @return
 */
 public T getInstance(HttpServletRequest request) throws Exception;
 /**
 * 進行驗證,沒拋異常說明驗證無誤
 * @return
 */
 public void checkIdentifying(HttpServletRequest request) throws Exception;
 /**
 * 獲取驗證結果,如果成功則為success,失敗則為失敗信息
 * @return
 */
 public String getCheckResult();
 /**
 * 獲取驗證碼的業務類型
 * @return
 */
 public String getIdentifyingType();
}

然后,設計一個具體的滑動驗證類去實現這個接口,這里只貼參數:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* @author NiceBin
* @description: 驗證碼類,前端需要生成驗證碼的信息
* @date 2019/7/12 16:04
*/
public class ImgIdentifying implements I_Identifying<ImgIdentifying>,Serializable {
 //此次驗證碼的id
 private String identifyingId;
 //此次驗證碼的業務類型
 private String identifyingType;
 //需要使用的圖片
 private String imgSrc;
 //生成塊的x坐標
 private int X;
 //生成塊的y坐標
 private int Y;
 //允許的誤差
 private int deviation = 2;
 //驗證碼生成的時間
 private Calendar calendar;
 //驗證碼結果,如果有結果說明已經被校驗,防止因為網絡延時的二次校驗
 private String checkResult;
 
 //下面是邏輯代碼...
}

上面每個變量都是一種校驗手段,如calendar可以檢驗驗證碼是否過期,identifyingType檢驗此驗證碼是否是對應的業務等。每多想一點,別人破解就多費勁一點。

后端驗證碼的驗證是不需要具體的類去調用的,而是被一個過濾器統一過濾,才過濾器注冊的時候,將需要進行驗證的路徑寫進去即可,過濾器代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
r NiceBin
 * @description: 驗證碼過濾器,幫忙驗證有需要驗證碼的請求,不幫忙生成驗證碼
 * @date 2019/7/23 15:06
 */
 @Component
 public class IdentifyingInterceptor implements HandlerInterceptor {
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
   HttpSession session = request.getSession();
   I_Identifying identifying= (I_Identifying)session.getAttribute(I_Identifying.IDENTIFYING);
   if(identifying!=null){
    identifying.checkIdentifying(request);
   }else {
    //應該攜帶驗證碼信息的,結果沒有攜帶,那就是個非法請求
    return false;
   }
   return true;
  }
  @Override
  public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
  }
  @Override
  public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
  }
 }

 

可以看到接口的用處了,之前在用戶申請驗證碼時,驗證碼類是放到用戶session中的,所以這里直接取出調用checkIdentifying即可,不需要關系它到底是滑動驗證碼,還是圖片驗證碼什么的。

總結

以上所述是小編給大家介紹的滑動驗證碼的設計與理解,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對服務器之家網站的支持!
如果你覺得本文對你有幫助,歡迎轉載,煩請注明出處,謝謝!

原文鏈接:https://www.cnblogs.com/top-housekeeper/p/11392439.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 综合另类| 欧美成人影院 | 欧美日韩电影一区二区三区 | 日本在线免费视频 | 91国自产精品中文字幕亚洲 | 欧美精品在线看 | 色视频在线免费观看 | 秋霞电影院午夜伦 | 久久亚洲一区二区三区明星换脸 | 91精品国产综合久久香蕉 | 极品一区 | 91精品国产综合久久久久久丝袜 | 日韩精品中文字幕在线 | 国内精品视频 | 91精品国产91久久综合 | 国产亚洲一区二区精品 | 精品综合99久久久久久www | 99视频在线免费观看 | 污片网站| 午夜影院在线 | 国产一区二区三区午夜 | 精品福利一区二区三区免费视频 | 成人教育av| 国产精品视频久久 | 一本大道久久a久久精二百 国产欧美视频一区二区 | 久久福利 | 中文字幕三区 | 精品国产91乱码一区二区三区 | 91羞羞网站| 国产一区二区精品在线观看 | 亚洲国产精品久久久久秋霞蜜臀 | 中文字幕在线观看视频地址二 | 亚洲成人久久久 | 97久久精品午夜一区二区 | av超碰 | 亚洲电影天堂在线观看 | 国产噜噜噜噜噜久久久久久久久 | 亚洲欧美在线观看 | 欧美色欧美亚洲另类七区 | 日韩一级精品视频在线观看 | 中文字幕一区二区三区不卡 |