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中Flask框架简单入门实例
Mar 21 Python
Python中使用tarfile压缩、解压tar归档文件示例
Apr 05 Python
一篇文章入门Python生态系统(Python新手入门指导)
Dec 11 Python
Python中operator模块的操作符使用示例总结
Jun 28 Python
Python对List中的元素排序的方法
Apr 01 Python
linux下python使用sendmail发送邮件
May 22 Python
Python面向对象之类的定义与继承用法示例
Jan 14 Python
Pytorch 实现计算分类器准确率(总分类及子分类)
Jan 18 Python
使用Python制作新型冠状病毒实时疫情图
Jan 28 Python
Anaconda安装pytorch及配置PyCharm 2021环境
Jun 04 Python
python 爬取天气网卫星图片
Jun 07 Python
python使用PySimpleGUI设置进度条及控件使用
Jun 10 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获取php,mysql,apche的版本信息示例代码
2014/01/16 PHP
php中利用explode函数分割字符串到数组
2014/02/08 PHP
php ci框架中加载css和js文件失败的原因及解决方法
2014/07/29 PHP
不用ajax实现点击文字即可编辑的方法
2007/12/16 Javascript
Javascript 继承机制实例
2009/08/12 Javascript
js 数组实现一个类似ruby的迭代器
2009/10/27 Javascript
扩展jQuery 键盘事件的几个基本方法
2009/10/30 Javascript
cloudgamer出品ImageZoom 图片放大效果
2010/04/01 Javascript
cument.execCommand()用法深入理解
2012/12/04 Javascript
JavaScript实现查找字符串中第一个不重复的字符
2014/12/29 Javascript
使用jquery+CSS实现控制打印样式
2014/12/31 Javascript
jQuery中slice()方法用法实例
2015/01/07 Javascript
AngularJS中下拉框的高级用法示例
2017/10/11 Javascript
prototype.js简单实现ajax功能示例
2017/10/18 Javascript
VueJs里利用CryptoJs实现加密及解密的方法示例
2019/04/29 Javascript
node实现爬虫的几种简易方式
2019/08/22 Javascript
Vue表单控件数据绑定方法详解
2020/02/05 Javascript
node爬取新型冠状病毒的疫情实时动态
2020/02/06 Javascript
JS数组方法reduce的用法实例分析
2020/03/03 Javascript
Python基于正则表达式实现文件内容替换的方法
2017/08/30 Python
python 读取txt中每行数据,并且保存到excel中的实例
2018/04/29 Python
python爬取个性签名的方法
2018/06/17 Python
Python中Proxypool库的安装与配置
2018/10/19 Python
pandas读取csv文件提示不存在的解决方法及原因分析
2020/04/21 Python
Python基于Hypothesis测试库生成测试数据
2020/04/29 Python
Python3实现个位数字和十位数字对调, 其乘积不变
2020/05/03 Python
matplotlib教程——强大的python作图工具库
2020/10/15 Python
加拿大在线隐形眼镜专家:PerfectLens.ca
2016/11/19 全球购物
印度化妆品购物网站:Nykaa
2018/07/22 全球购物
英国医生在线预约:Top Doctors
2019/10/30 全球购物
什么是Deployment descriptors;都有什么类型的部署描述符
2015/07/28 面试题
行政专员工作职责
2013/12/22 职场文书
汇报材料怎么写
2014/12/30 职场文书
2019年公司快递收发管理制度模板
2019/11/20 职场文书
导游词之镜泊湖
2019/12/09 职场文书
python获取带有返回值的多线程
2022/05/02 Python