Django中使用极验Geetest滑动验证码过程解析


Posted in Python onJuly 31, 2019

一,环境部署

1.创建一个django测试项目

二,文档部署

1.下载安装python对应的SDK

使用命令从Github导入完整项目:git clone https://github.com/GeeTeam/gt3-python-sdk.git

手动下载压缩包文件:https://github.com/GeeTeam/gt3-python-sdk/archive/master.zip

2.参数配置

修改请求参数(可选)

名称 说明
user_id 用户标识,若担心用户信息风险,可作预处理(如哈希处理)再提供
client_type 客户端类型,web(pc浏览器),h5(手机浏览器,包括webview),native(原生app),unknown(未知)
ip_address 客户端请求您服务器的ip地址,unknow表示未知

三.代码实现 

SDK:utils>geetest.py

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()

view.py

# _*_ coding=utf-8 _*_
import uuid, json
from rest_framework.views import APIView
from rest_framework.response import Response
from api.models import Account, UserToken
from django_redis import get_redis_connection
from django.http import HttpResponse
from api.utils.geetest import GeetestLib
# id和key需要在Geetest官网自行申请,示例id不可用
pc_geetest_id = "b46d1900d0a894591916ea94ea91bd2c"
pc_geetest_key = "36fc3fe98530eea08dfc6ce76e3d24c4"
REDIS_CONN = get_redis_connection('default')
class GeetestView(APIView):

  def get(self, request):
    user_id = 'test'
    gt = GeetestLib(pc_geetest_id, pc_geetest_key)
    status = gt.pre_process(user_id)
    # 使用session
    # request.session[gt.GT_STATUS_SESSION_KEY] = status
    # request.session["user_id"] = user_id
    # 使用redis
    REDIS_CONN.set(gt.GT_STATUS_SESSION_KEY, status)
    REDIS_CONN.set("gt_user_id", user_id)
    response_str = gt.get_response_str()
    return HttpResponse(response_str)

  def post(self, request):
    # print(request.session.get("user_id"))
    print(request.META.get("HTTP_AUTHENTICATION"))
    print(request.data)
    gt = GeetestLib(pc_geetest_id, pc_geetest_key)
    challenge = request.data.get(gt.FN_CHALLENGE, '')
    validate = request.data.get(gt.FN_VALIDATE, '')
    seccode = request.data.get(gt.FN_SECCODE, '')
    # 验证username,pwd
    # status = request.session.get(gt.GT_STATUS_SESSION_KEY)
    # print(status)
    # user_id = request.session.get("user_id")
    # print(user_id)
    status = REDIS_CONN.get(gt.GT_STATUS_SESSION_KEY)
    user_id = REDIS_CONN.get("gt_user_id")
    if status:
      result = gt.success_validate(challenge, validate, seccode, user_id)
    else:
      result = gt.failback_validate(challenge, validate, seccode)
    result = {"status": "success"} if result else {"status": "fail"}
    # if result:
    #   # 证明验证码通过
    #   # 判断用户名和密码
    # else:
    #   # 返回验证码错误
    return HttpResponse(json.dumps(result))

url.py

path('pc-geetest/register', GeetestView.as_view()),
path('pc-geetest/ajax_validate', GeetestView.as_view()),

login.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Title</title>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script src="http://static.geetest.com/static/tools/gt.js"></script>
  <script src="https://cdn.bootcss.com/axios/0.19.0-beta.1/axios.js"></script>
  <style>
    body {
      margin: 50px 0;
      text-align: center;
    }

    .inp {
      border: 1px solid gray;
      padding: 0 10px;
      width: 200px;
      height: 30px;
      font-size: 18px;
    }

    .btn {
      border: 1px solid gray;
      width: 100px;
      height: 30px;
      font-size: 18px;
      cursor: pointer;
    }

    #embed-captcha {
      width: 300px;
      margin: 0 auto;
    }

    .show {
      display: block;
    }

    .hide {
      display: none;
    }

    #notice {
      color: red;
    }

    /* 以下遮罩层为demo.用户可自行设计实现 */
    #mask {
      display: none;
      position: fixed;
      text-align: center;
      left: 0;
      top: 0;
      width: 100%;
      height: 100%;
      background-color: rgba(0, 0, 0, 0.5);
      overflow: auto;
    }

    /* 可自行设计实现captcha的位置大小 */
    .popup-mobile {
      position: relative;
    }

    #popup-captcha-mobile {
      position: fixed;
      display: none;
      left: 50%;
      top: 50%;
      transform: translate(-50%, -50%);
      -webkit-transform: translate(-50%, -50%);
      z-index: 9999;
    }
  </style>


</head>
<body>
<div id="app">
  <div class="popup">
    <h2>弹出式Demo,使用ajax形式提交二次验证码所需的验证结果值</h2>
    <br>
    <p>
      <label>用户名:</label>
      <input id="username1" class="inp" type="text" value="极验验证" v-model="username">
    </p>
    <br>
    <p>
      <label>密    码:</label>
      <input id="password1" class="inp" type="password" value="123456" v-model="pwd">
    </p>

    <br>
    <input class="btn" id="popup-submit" type="submit" value="提交" ref="popup">

    <div id="popup-captcha"></div>
  </div>
</div>
<script>
  // Vue.prototype.$axios = axios;
  const app = new Vue({
    el: "#app",
    data: {
      username: "极验验证",
      pwd: "123456"
    },
    mounted() {
      let that = this;

      // 验证开始需要向网站主后台获取id,challenge,success(是否启用failback)
      axios.request({
        url: "http://127.0.0.1:8008/pc-geetest/register?t=" + (new Date()).getTime(), // 加随机数防止缓存
        method: "get",
      }).then(function (data) {
        console.log(data.data);
        // 使用initGeetest接口
        // 参数1:配置参数
        // 参数2:回调,回调的第一个参数验证码对象,之后可以使用它做appendTo之类的事件
        initGeetest({
          gt: data.data.gt,
          challenge: data.data.challenge,
          product: "popup", // 产品形式,包括:float,embed,popup。注意只对PC版验证码有效
          offline: !data.data.success, // 表示用户后台检测极验服务器是否宕机,一般不需要关注
          new_captcha: true
          // 更多配置参数请参见:http://www.geetest.com/install/sections/idx-client-sdk.html#config
        }, function (captchaObj) {
          // 成功的回调
          console.log("进入成功的回调");
          captchaObj.onSuccess(function () {
            let validate = captchaObj.getValidate();
            console.log(122233333)
            axios.request({
              url: "http://127.0.0.1:8008/pc-geetest/ajax_validate", // 进行二次验证
              method: "post",
              data: {
                username: that.username,
                password: that.pwd,
                geetest_challenge: validate.geetest_challenge,
                geetest_validate: validate.geetest_validate,
                geetest_seccode: validate.geetest_seccode
              }
            }).then(function (data) {
              console.log(data.data);
              if (data && (data.data.status === "success")) {
                alert("登录成功")
              } else {
                alert("登录失败")
              }
            })
          });
          console.log(that.$refs.popup);
          that.$refs.popup.onclick = function () {
            captchaObj.show();
          };
          // 将验证码加到id为captcha的元素里
          captchaObj.appendTo("#popup-captcha");
          // 更多接口参考:http://www.geetest.com/install/sections/idx-client-sdk.html
        });
      })


    }

  })
</script>
</body>
</html>

Django中使用极验Geetest滑动验证码过程解析

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python中几个比较常见的名词解释
Jul 04 Python
python fabric实现远程部署
Jan 05 Python
深入理解Python中的内置常量
May 20 Python
Python 查看文件的编码格式方法
Dec 21 Python
tensorflow实现softma识别MNIST
Mar 12 Python
python中不能连接超时的问题及解决方法
Jun 10 Python
对PyTorch torch.stack的实例讲解
Jul 30 Python
python 实现语音聊天机器人的示例代码
Dec 02 Python
Python判断有效的数独算法示例
Feb 23 Python
Python解压 rar、zip、tar文件的方法
Nov 19 Python
Pycharm配置PyQt5环境的教程
Apr 02 Python
python脚本和网页有何区别
Jul 02 Python
Python对接六大主流数据库(只需三步)
Jul 31 #Python
Python爬虫 scrapy框架爬取某招聘网存入mongodb解析
Jul 31 #Python
python爬虫 模拟登录人人网过程解析
Jul 31 #Python
Python爬虫 bilibili视频弹幕提取过程详解
Jul 31 #Python
Django实现跨域的2种方法
Jul 31 #Python
Django CSRF跨站请求伪造防护过程解析
Jul 31 #Python
在VS2017中用C#调用python脚本的实现
Jul 31 #Python
You might like
php面向对象全攻略 (五) 封装性
2009/09/30 PHP
php连接mssql的一些相关经验及注意事项
2013/02/05 PHP
php封装的单文件(图片)上传类完整实例
2016/10/18 PHP
为何说PHP引用是个坑,要慎用
2018/04/02 PHP
Yii2框架实现登陆添加验证码功能示例
2018/07/12 PHP
PHP后台实现微信小程序登录
2018/08/03 PHP
jQuery使用手册之三 CSS操作
2007/03/24 Javascript
一个用js实现的页内搜索代码
2007/05/23 Javascript
JavaScript入门教程(2) JS基础知识
2009/01/31 Javascript
javascript json2 使用方法
2010/03/16 Javascript
jquery remove方法应用详解
2012/11/22 Javascript
简单选项卡 js和jquery制作方法分享
2014/02/26 Javascript
jquery实现适用于门户站的导航下拉菜单效果代码
2015/08/24 Javascript
JS中frameset框架弹出层实例代码
2016/04/01 Javascript
js实现按钮控制带有停顿效果的图片滚动
2016/08/30 Javascript
Angular2学习教程之组件中的DOM操作详解
2017/05/28 Javascript
Vue2.0 给Tab标签页和页面切换过渡添加样式的方法
2018/03/13 Javascript
微信小程序之几种常见的弹框提示信息实现详解
2019/07/11 Javascript
node.js使用fs读取文件出错的解决方案
2019/10/23 Javascript
JS访问对象两种方式区别解析
2020/08/29 Javascript
js定时器出现第一次延迟的原因及解决方法
2021/01/04 Javascript
在Django中使用Sitemap的方法讲解
2015/07/22 Python
python中模块的__all__属性详解
2017/10/26 Python
Python格式化日期时间操作示例
2018/06/28 Python
python使用正则筛选信用卡
2019/01/27 Python
python实现微信防撤回神器
2019/04/29 Python
在脚本中单独使用django的ORM模型详解
2020/04/01 Python
Python+Xlwings 删除Excel的行和列
2020/12/19 Python
使用HTML5 Canvas API绘制弧线的教程
2016/03/22 HTML / CSS
分别介绍一下Session Bean和Entity Bean
2015/03/13 面试题
医大实习自我鉴定
2013/12/07 职场文书
护理实习自我鉴定
2013/12/14 职场文书
采购类个人求职的自我评价
2014/02/18 职场文书
小学语文教学随笔
2015/08/14 职场文书
《天净沙·秋思》教学反思三篇
2019/11/02 职场文书
HTML5简单实现添加背景音乐的几种方法
2021/05/12 HTML / CSS