极验验证码(geetest)和django之间的使用

极验验证码如何使用

  1. sdk的github地址 git clone https://github.com/GeeTeam/gt3-python-sdk.git

  2. 官网申请账号点此进入,并获取id和key

  3. 项目配置文件

    # GeeTest
    GEETEST_PC_ID = 'b46d1900d0a894591916ea94ea91bd2c'
    GEETEST_PC_KEY = '36fc3fe98530eea08dfc6ce76e3d24c4'
    
  4. 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()
    
  5. 后端代码-获取滑动验证码

    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)
    
  6. 后端代码-验证验证码和数据信息

    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"})
    
  7. 前端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);
      }
    });
    
  8. 最终实现的效果如图

posted @ 2020-02-19 14:41  巫小诗  阅读(647)  评论(0编辑  收藏  举报