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使用datetime模块计算各种时间间隔的方法
Mar 24 Python
简单介绍Python的Django框架加载模版的方式
Jul 20 Python
使用python实现生成用户信息
Mar 20 Python
python数据结构之列表和元组的详解
Sep 23 Python
Python网络爬虫中的同步与异步示例详解
Feb 03 Python
几行Python代码爬取3000+上市公司的信息
Jan 24 Python
numpy.meshgrid()理解(小结)
Aug 01 Python
pytorch实现onehot编码转为普通label标签
Jan 02 Python
python GUI库图形界面开发之PyQt5选项卡控件QTabWidget详细使用方法与实例
Mar 01 Python
python实现图像拼接功能
Mar 23 Python
python mysql中in参数化说明
Jun 05 Python
Pycharm plot独立窗口显示的操作
Dec 11 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基础知识:类与对象(1)
2006/12/13 PHP
IIS php环境配置PHP5 MySQL5 ZendOptimizer phpmyadmin安装与配置
2008/11/18 PHP
array_multisort实现PHP多维数组排序示例讲解
2011/01/04 PHP
PHP取整数函数常用的四种方法小结
2012/07/05 PHP
js操作ajax返回的json的注意问题!
2010/02/23 Javascript
分享一个自己写的table表格排序js插件(高效简洁)
2011/10/29 Javascript
如何使用jQuery Draggable和Droppable实现拖拽功能
2013/07/05 Javascript
鼠标移动到图片名上,显示图片的简单实例
2013/07/14 Javascript
Javascript实现带关闭按钮的网页漂浮广告代码
2014/01/12 Javascript
JS判断移动端访问设备并加载对应CSS样式
2014/06/13 Javascript
JQuery的attr 与 val区别
2016/06/12 Javascript
jquery-mobile基础属性与用法详解
2016/11/23 Javascript
如何实现星星评价(jquery.raty.js插件)
2016/12/21 Javascript
js编写选项卡效果
2017/05/23 Javascript
详解基于 Nuxt 的 Vue.js 服务端渲染实践
2017/10/24 Javascript
基于vue2的canvas时钟倒计时组件步骤解析
2018/11/05 Javascript
Vue中实现权限控制的方法示例
2019/06/07 Javascript
微信小程序实现选择地址省市区三级联动
2020/06/21 Javascript
[10:05]DOTA2-DPC中国联赛 正赛 iG vs PSG.LGD 选手采访
2021/03/11 DOTA
[22:07]DOTA2-DPC中国联赛 正赛 iG vs Magma 选手采访
2021/03/11 DOTA
编写Python脚本来实现最简单的FTP下载的教程
2015/05/04 Python
Python爬虫之模拟知乎登录的方法教程
2017/05/25 Python
python 机器学习之支持向量机非线性回归SVR模型
2019/06/26 Python
Python Merge函数原理及用法解析
2020/09/16 Python
python在linux环境下安装skimage的示例代码
2020/10/14 Python
python 怎样进行内存管理
2020/11/10 Python
瑞典首都斯德哥尔摩的多元奢侈时尚品牌:Acne Studios
2017/07/09 全球购物
英国领先的在线药房:Pharmacy First
2017/09/10 全球购物
澳洲健康食品网上商店:Aussie Health Products
2018/06/15 全球购物
西班牙最好的在线购买葡萄酒的商店:Vinoseleccion
2019/10/30 全球购物
迟到检讨书1000字
2014/01/15 职场文书
法定代表人授权委托书范文
2014/08/02 职场文书
2014年客户经理工作总结
2014/11/20 职场文书
感谢信格式范文
2015/01/22 职场文书
python小型的音频操作库mp3Play
2022/04/24 Python
MySQL的存储过程和相关函数
2022/04/26 MySQL