一,登陸頁面爲何要有驗證碼?css
防止用戶惡意的頻繁向後端發送請求,使得服務端的壓力大增,避免沒必要要的請求壓力。html
以Django爲例,關於圖片驗證碼和滑動驗證碼的實現jquery
2、圖片驗證碼的實現ajax
路由部分 urls.pydjango
from django.conf.urls import url from django.contrib import admin from blog import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^login/', views.login), url(r'^index/',views.index), url(r'^get_valid_img/',views.get_valid_img), ]
視圖函數部分 views.pyjson
# 獲取驗證碼圖片的視圖 def get_valid_img(request): # with open("valid_code.png", "rb") as f: # data = f.read() # 本身生成一個圖片 from PIL import Image, ImageDraw, ImageFont import random # 獲取隨機顏色的函數 def get_random_color(): return random.randint(0, 255), random.randint(0, 255), random.randint(0, 255) # 生成一個圖片對象 img_obj = Image.new( 'RGB', (220, 35), get_random_color() ) # 在生成的圖片上寫字符 # 生成一個圖片畫筆對象 draw_obj = ImageDraw.Draw(img_obj) # 加載字體文件, 獲得一個字體對象 font_obj = ImageFont.truetype("static/font/kumo.ttf", 28) # 開始生成隨機字符串而且寫到圖片上 tmp_list = [] for i in range(5): u = chr(random.randint(65, 90)) # 生成大寫字母 l = chr(random.randint(97, 122)) # 生成小寫字母 n = str(random.randint(0, 9)) # 生成數字,注意要轉換成字符串類型 tmp = random.choice([u, l, n]) tmp_list.append(tmp) draw_obj.text((20+40*i, 0), tmp, fill=get_random_color(), font=font_obj) # print("".join(tmp_list)) # print("生成的驗證碼".center(120, "=")) # 不能保存到全局變量 # global VALID_CODE # VALID_CODE = "".join(tmp_list) # 保存到session request.session["valid_code"] = "".join(tmp_list) # 加干擾線 # width = 220 # 圖片寬度(防止越界) # height = 35 # for i in range(5): # x1 = random.randint(0, width) # x2 = random.randint(0, width) # y1 = random.randint(0, height) # y2 = random.randint(0, height) # draw_obj.line((x1, y1, x2, y2), fill=get_random_color()) # # # 加干擾點 # for i in range(40): # draw_obj.point((random.randint(0, width), random.randint(0, height)), fill=get_random_color()) # x = random.randint(0, width) # y = random.randint(0, height) # draw_obj.arc((x, y, x+4, y+4), 0, 90, fill=get_random_color()) # 將生成的圖片保存在磁盤上 # with open("s10.png", "wb") as f: # img_obj.save(f, "png") # # 把剛纔生成的圖片返回給頁面 # with open("s10.png", "rb") as f: # data = f.read() # 不須要在硬盤上保存文件,直接在內存中加載就能夠 from io import BytesIO io_obj = BytesIO() # 將生成的圖片數據保存在io對象中 img_obj.save(io_obj, "png") # 從io對象裏面取上一步保存的數據 data = io_obj.getvalue() return HttpResponse(data)
登陸驗證視圖函數bootstrap
def login(request): # if request.is_ajax(): # 若是是AJAX請求 if request.method == "POST": # 初始化一個給AJAX返回的數據 ret = {"status": 0, "msg": ""} # 從提交過來的數據中 取到用戶名和密碼 username = request.POST.get("username") pwd = request.POST.get("password") valid_code = request.POST.get("valid_code") # 獲取用戶填寫的驗證碼 # print(valid_code) # print("用戶輸入的驗證碼".center(120, "=")) if valid_code and valid_code.upper() == request.session.get("valid_code", "").upper(): # 驗證碼正確 # 利用auth模塊作用戶名和密碼的校驗 user = auth.authenticate(username=username, password=pwd) if user: # 用戶名密碼正確 # 給用戶作登陸 auth.login(request, user) ret["msg"] = "/index/" else: # 用戶名密碼錯誤 ret["status"] = 1 ret["msg"] = "用戶名或密碼錯誤!" else: ret["status"] = 1 ret["msg"] = "驗證碼錯誤" return JsonResponse(ret) return render(request, "login.html") def index(request): return render(request, "index.html")
模板部分 login.html後端
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>歡迎登陸</title> <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css"> <link rel="stylesheet" href="/static/mystyle.css"> </head> <body> <div class="container"> <div class="row"> <form class="form-horizontal col-md-6 col-md-offset-3 login-form"> {% csrf_token %} <div class="form-group"> <label for="username" class="col-sm-2 control-label">用戶名</label> <div class="col-sm-10"> <input type="text" class="form-control" id="username" name="username" placeholder="用戶名"> </div> </div> <div class="form-group"> <label for="password" class="col-sm-2 control-label">密碼</label> <div class="col-sm-10"> <input type="password" class="form-control" id="password" name="password" placeholder="密碼"> </div> </div> <div class="form-group"> <label for="password" class="col-sm-2 control-label">驗證碼</label> <div class="col-sm-10"> <input type="text" name="valid_code" id="valid_code"> <img id="valid-img" class="valid-img" src="/get_valid_img.png?" alt=""> </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <button type="button" class="btn btn-default" id="login-button">登陸</button> <span class="login-error"></span> </div> </div> </form> </div> </div> <script src="/static/jquery-3.3.1.js"></script> <script src="/static/bootstrap/js/bootstrap.min.js"></script> <script> $("#login-button").click(function () { // 1. 取到用戶填寫的用戶名和密碼 -> 取input框的值 var username = $("#username").val(); var password = $("#password").val(); var valid_code = $("#valid_code").val(); // 2. 用AJAX發送到服務端 $.ajax({ url: "/login/", type: "post", data: { "username": username, "password": password, "valid_code": valid_code, "csrfmiddlewaretoken": $("[name='csrfmiddlewaretoken']").val() }, success: function (data) { console.log(data); if (data.status){ // 有錯誤,在頁面上提示 $(".login-error").text(data.msg); }else { // 登錄成功 location.href = data.msg; } } }) }); // 當input框獲取焦點時將以前的錯誤清空 $("#username,#password").focus(function () { // 將以前的錯誤清空 $(".login-error").text(""); }); // 點擊驗證碼圖片 刷新驗證碼 $("#valid-img").click(function () { $(this)[0].src += "?"; }) </script> </body> </html>
3、極驗滑動驗證碼緩存
路由部分服務器
from django.conf.urls import url from django.contrib import admin from blog import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^login/', views.login), url(r'^index/', views.index), # 極驗滑動驗證碼 獲取驗證碼的url url(r'^pc-geetest/register', views.get_geetest), ]
視圖函數部分
獲取滑動驗證碼函數
# 導入模塊
from geetest import GeetestLib
# 請在官網申請ID使用,示例ID不可以使用 pc_geetest_id = "b46d1900d0a894591916ea94ea91bd2c" pc_geetest_key = "36fc3fe98530eea08dfc6ce76e3d24c4" # 處理極驗 獲取驗證碼的視圖 def get_geetest(request): user_id = 'test' gt = GeetestLib(pc_geetest_id, pc_geetest_key) status = gt.pre_process(user_id) request.session[gt.GT_STATUS_SESSION_KEY] = status request.session["user_id"] = user_id response_str = gt.get_response_str() return HttpResponse(response_str)
校驗驗證碼函數
# 使用極驗滑動驗證碼的登陸 def login(request): # if request.is_ajax(): # 若是是AJAX請求 if request.method == "POST": # 初始化一個給AJAX返回的數據 ret = {"status": 0, "msg": ""} # 從提交過來的數據中 取到用戶名和密碼 username = request.POST.get("username") pwd = request.POST.get("password") # 獲取極驗 滑動驗證碼相關的參數 gt = GeetestLib(pc_geetest_id, pc_geetest_key) challenge = request.POST.get(gt.FN_CHALLENGE, '') validate = request.POST.get(gt.FN_VALIDATE, '') seccode = request.POST.get(gt.FN_SECCODE, '') status = request.session[gt.GT_STATUS_SESSION_KEY] user_id = request.session["user_id"] if status: result = gt.success_validate(challenge, validate, seccode, user_id) else: result = gt.failback_validate(challenge, validate, seccode) if result: # 驗證碼正確 # 利用auth模塊作用戶名和密碼的校驗 user = auth.authenticate(username=username, password=pwd) if user: # 用戶名密碼正確 # 給用戶作登陸 auth.login(request, user) ret["msg"] = "/index/" else: # 用戶名密碼錯誤 ret["status"] = 1 ret["msg"] = "用戶名或密碼錯誤!" else: ret["status"] = 1 ret["msg"] = "驗證碼錯誤" return JsonResponse(ret) return render(request, "login2.html") def index(request): return render(request, "index.html")
模板部分
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>歡迎登陸</title> <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css"> <link rel="stylesheet" href="/static/mystyle.css"> </head> <body> <div class="container"> <div class="row"> <form class="form-horizontal col-md-6 col-md-offset-3 login-form"> {% csrf_token %} <div class="form-group"> <label for="username" class="col-sm-2 control-label">用戶名</label> <div class="col-sm-10"> <input type="text" class="form-control" id="username" name="username" placeholder="用戶名"> </div> </div> <div class="form-group"> <label for="password" class="col-sm-2 control-label">密碼</label> <div class="col-sm-10"> <input type="password" class="form-control" id="password" name="password" placeholder="密碼"> </div> </div> <div class="form-group"> <!-- 放置極驗的滑動驗證碼 --> <div id="popup-captcha"></div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <button type="button" class="btn btn-default" id="login-button">登陸</button> <span class="login-error"></span> </div> </div> </form> </div> </div> <script src="/static/jquery-3.3.1.js"></script> <script src="/static/bootstrap/js/bootstrap.min.js"></script> <!-- 引入封裝了failback的接口--initGeetest --> <script src="http://static.geetest.com/static/tools/gt.js"></script> <script> // 極驗 發送登陸數據的 var handlerPopup = function (captchaObj) { // 成功的回調 captchaObj.onSuccess(function () { var validate = captchaObj.getValidate(); // 1. 取到用戶填寫的用戶名和密碼 -> 取input框的值 var username = $("#username").val(); var password = $("#password").val(); $.ajax({ url: "/login/", // 進行二次驗證 type: "post", dataType: "json", data: { username: username, password: password, csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val(), geetest_challenge: validate.geetest_challenge, geetest_validate: validate.geetest_validate, geetest_seccode: validate.geetest_seccode }, success: function (data) { console.log(data); if (data.status) { // 有錯誤,在頁面上提示 $(".login-error").text(data.msg); } else { // 登錄成功 location.href = data.msg; } } }); }); $("#login-button").click(function () { captchaObj.show(); }); // 將驗證碼加到id爲captcha的元素裏 captchaObj.appendTo("#popup-captcha"); // 更多接口參考:http://www.geetest.com/install/sections/idx-client-sdk.html }; // 當input框獲取焦點時將以前的錯誤清空 $("#username,#password").focus(function () { // 將以前的錯誤清空 $(".login-error").text(""); }); // 驗證開始須要向網站主後臺獲取id,challenge,success(是否啓用failback) $.ajax({ url: "/pc-geetest/register?t=" + (new Date()).getTime(), // 加隨機數防止緩存 type: "get", dataType: "json", success: function (data) { // 使用initGeetest接口 // 參數1:配置參數 // 參數2:回調,回調的第一個參數驗證碼對象,以後可使用它作appendTo之類的事件 initGeetest({ gt: data.gt, challenge: data.challenge, product: "popup", // 產品形式,包括:float,embed,popup。注意只對PC版驗證碼有效 offline: !data.success // 表示用戶後臺檢測極驗服務器是否宕機,通常不須要關注 // 更多配置參數請參見:http://www.geetest.com/install/sections/idx-client-sdk.html#config }, handlerPopup); } }) </script> </body> </html>