极验验证码(geetest)和django之间的使用
极验验证码如何使用
-
sdk的github地址
git clone https://github.com/GeeTeam/gt3-python-sdk.git
-
官网申请账号点此进入,并获取id和key
-
项目配置文件
# GeeTest GEETEST_PC_ID = 'b46d1900d0a894591916ea94ea91bd2c' GEETEST_PC_KEY = '36fc3fe98530eea08dfc6ce76e3d24c4'
-
geetest 核心文件
#!coding:utf8 import sys import random import json import requests import time from hashlib import md5 if sys.version_info >= (3,): xrange = range VERSION = "3.0.0" class GeetestLib(object): FN_CHALLENGE = "geetest_challenge" FN_VALIDATE = "geetest_validate" FN_SECCODE = "geetest_seccode" GT_STATUS_SESSION_KEY = "gt_server_status" API_URL = "http://api.geetest.com" REGISTER_HANDLER = "/register.php" VALIDATE_HANDLER = "/validate.php" JSON_FORMAT = False def __init__(self, captcha_id, private_key): self.private_key = private_key self.captcha_id = captcha_id self.sdk_version = VERSION self._response_str = "" def pre_process(self, user_id=None,new_captcha=1,JSON_FORMAT=1,client_type="web",ip_address=""): """ 验证初始化预处理. //TO DO arrage the parameter """ status, challenge = self._register(user_id,new_captcha,JSON_FORMAT,client_type,ip_address) self._response_str = self._make_response_format(status, challenge,new_captcha) return status def _register(self, user_id=None,new_captcha=1,JSON_FORMAT=1,client_type="web",ip_address=""): pri_responce = self._register_challenge(user_id,new_captcha,JSON_FORMAT,client_type,ip_address) if pri_responce: if JSON_FORMAT == 1: response_dic = json.loads(pri_responce) challenge = response_dic["challenge"] else: challenge = pri_responce else: challenge=" " if len(challenge) == 32: challenge = self._md5_encode("".join([challenge, self.private_key])) return 1,challenge else: return 0, self._make_fail_challenge() def get_response_str(self): return self._response_str def _make_fail_challenge(self): rnd1 = random.randint(0, 99) rnd2 = random.randint(0, 99) md5_str1 = self._md5_encode(str(rnd1)) md5_str2 = self._md5_encode(str(rnd2)) challenge = md5_str1 + md5_str2[0:2] return challenge def _make_response_format(self, success=1, challenge=None,new_captcha=1): if not challenge: challenge = self._make_fail_challenge() if new_captcha: string_format = json.dumps( {'success': success, 'gt':self.captcha_id, 'challenge': challenge,"new_captcha":True}) else: string_format = json.dumps( {'success': success, 'gt':self.captcha_id, 'challenge': challenge,"new_captcha":False}) return string_format def _register_challenge(self, user_id=None,new_captcha=1,JSON_FORMAT=1,client_type="web",ip_address=""): if user_id: register_url = "{api_url}{handler}?gt={captcha_ID}&user_id={user_id}&json_format={JSON_FORMAT}&client_type={client_type}&ip_address={ip_address}".format( api_url=self.API_URL, handler=self.REGISTER_HANDLER, captcha_ID=self.captcha_id, user_id=user_id,new_captcha=new_captcha,JSON_FORMAT=JSON_FORMAT,client_type=client_type,ip_address=ip_address) else: register_url = "{api_url}{handler}?gt={captcha_ID}&json_format={JSON_FORMAT}&client_type={client_type}&ip_address={ip_address}".format( api_url=self.API_URL, handler=self.REGISTER_HANDLER, captcha_ID=self.captcha_id,new_captcha=new_captcha,JSON_FORMAT=JSON_FORMAT,client_type=client_type,ip_address=ip_address) try: response = requests.get(register_url, timeout=2) if response.status_code == requests.codes.ok: res_string = response.text else: res_string = "" except: res_string = "" return res_string def success_validate(self, challenge, validate, seccode, user_id=None,gt=None,data='',userinfo='',JSON_FORMAT=1): """ 正常模式的二次验证方式.向geetest server 请求验证结果. """ if not self._check_para(challenge, validate, seccode): return 0 if not self._check_result(challenge, validate): return 0 validate_url = "{api_url}{handler}".format( api_url=self.API_URL, handler=self.VALIDATE_HANDLER) query = { "seccode": seccode, "sdk": ''.join( ["python_",self.sdk_version]), "user_id": user_id, "data":data, "timestamp":time.time(), "challenge":challenge, "userinfo":userinfo, "captchaid":gt, "json_format":JSON_FORMAT } backinfo = self._post_values(validate_url, query) if JSON_FORMAT == 1: backinfo = json.loads(backinfo) backinfo = backinfo["seccode"] if backinfo == self._md5_encode(seccode): return 1 else: return 0 def _post_values(self, apiserver, data): response = requests.post(apiserver, data) return response.text def _check_result(self, origin, validate): encodeStr = self._md5_encode(self.private_key + "geetest" + origin) if validate == encodeStr: return True else: return False def failback_validate(self, challenge, validate, seccode): """ failback模式的二次验证方式.在本地对轨迹进行简单的判断返回验证结果. """ if not self._check_para(challenge, validate, seccode): return 0 validate_result = self._failback_check_result( challenge, validate,) return validate_result def _failback_check_result(self,challenge,validate): encodeStr = self._md5_encode(challenge) if validate == encodeStr: return True else: return False def _check_para(self, challenge, validate, seccode): return (bool(challenge.strip()) and bool(validate.strip()) and bool(seccode.strip())) def _md5_encode(self, values): if type(values) == str: values = values.encode() m = md5(values) return m.hexdigest()
-
后端代码-获取滑动验证码
def get(self,request): user_id = 'test' gt = GeetestLib(settings.GEETEST_PC_ID, settings.GEETEST_PC_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 post(self,request): # 判断用户名和密码不能为空 name = request.POST.get("username", "").strip() if not name: return Response({"status": "fail","msg":"用户名不能为空"}) password = request.POST.get("password", "").strip() if not re.match(r'\w{5,16}',password): return Response({"status": "fail", "msg": "密码不合法"}) gt = GeetestLib(settings.GEETEST_PC_ID, settings.GEETEST_PC_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 not result: return Response({"status": "fail","msg":"网络错误"}) # 检查用户是否存在 userobj = models.Member.objects.filter(name=name).first() if not userobj: return Response({"status": "fail", "msg": "用户名或者密码错误"}) if not check_password(password,userobj.password): return Response({"status": "fail","msg":"用户名或者密码错误"}) # 将name存在session中 request.session['uname'] = name return Response({"status": "success"})
-
前端js实现
var handlerPopup = function (captchaObj) { // 成功的回调 captchaObj.onSuccess(function () { var validate = captchaObj.getValidate(); $.ajax({ url: "/geetest/", // 进行二次验证 type: "post", dataType: "json", data: { username: $('#username1').val(), password: $('#password1').val(), geetest_challenge: validate.geetest_challenge, geetest_validate: validate.geetest_validate, geetest_seccode: validate.geetest_seccode }, success: function (data) { if (data && (data.status === "success")) { location.href = '/day/'; } else { var html = "<h6>"+data.msg+"</h6>"; $(".modal-body p").html(html); $("#myModal").modal("show"); } } }); }); $("#popup-submit").click(function () { captchaObj.show(); }); // 将验证码加到id为captcha的元素里 captchaObj.appendTo("#popup-captcha"); }; // 项目初始化 调用geettest接口 $.ajax({ url: "/geetest/?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 // 表示用户后台检测极验服务器是否宕机,一般不需要关注 }, handlerPopup); } });
-
最终实现的效果如图