├── README.md ├── README.rst └── demo ├── django_demo ├── app │ ├── __init__.py │ ├── __init__.pyc │ └── views.py ├── db.sqlite3 ├── django_demo │ ├── __init__.py │ ├── __init__.pyc │ ├── settings.py │ ├── settings.pyc │ ├── urls.py │ ├── urls.pyc │ └── wsgi.py ├── geetest │ ├── __init__.py │ └── geetest.py ├── manage.py ├── requirements.txt └── static │ ├── gt.js │ └── index.html ├── flask_demo ├── geetest │ ├── __init__.py │ └── geetest.py ├── requirements.txt ├── start.py ├── static │ └── gt.js └── templates │ └── login.html └── tornado_demo ├── geetest ├── __init__.py └── geetest.py ├── requirements.txt ├── start.py └── static ├── gt.js └── login.html /README.md: -------------------------------------------------------------------------------- 1 | # Gt3 Python SDK 2 | 3 | # 概述 4 | 5 | > 行为验证 Python SDK目前提供基于`Flask`、`Tornado`、`Django`框架的demo。 6 | 7 | ## 开发环境 8 | 9 | |条目|| 10 | |----|------| 11 | |python环境 | python3,建议python3.5| 12 | |依赖库|Web框架库(如`django`、`tornado`)等
您可以使用`pip3 install -r requirements.txt` 一键安装所有依赖| 13 | 14 | ## 资源导航 15 | 16 | |条目|| 17 | |-------------|--------------| 18 | |产品结构流程|[通讯流程](/install/overview/flowchart/#通讯流程)| 19 | |SDK项目地址|[gt3-python-sdk](http://github.com/GeeTeam/gt3-python-sdk)| 20 | 21 | # 安装 Python SDK 22 | 23 | ## 下载SDK 24 | 25 | > 使用命令从Github导入完整项目 26 | 27 | ``` 28 | git clone https://github.com/GeeTeam/gt3-python-sdk.git 29 | ``` 30 | 31 | > 手动下载压缩包文件 32 | 33 | 从[Github: gt3-python-sdk](https://github.com/GeeTeam/gt3-python-sdk/archive/master.zip)下载`.zip`文件 34 | 35 | ## 下载pip依赖 36 | 37 | > 各框架demo路径中有requirements.txt文件,使用pip3一键安装 38 | 39 | ``` 40 | pip3 install -r requirements.txt 41 | ``` 42 | 43 | ## 配置密钥,修改请求参数 44 | 45 | > 配置密钥 46 | 47 | 从[极验管理后台](https://account.geetest.com/login)获取您的公钥(id)和私钥(key), 并在代码中配置。配置文件路径如下: 48 | - Django:`/demo/django_demo/app/views.py` 49 | - Flask:`/demo/flask_demo/start.py` 50 | - Tornado:`/demo/tornado_demo/start.py` 51 | 52 | > 修改请求参数(可选) 53 | 54 | 名称|说明 55 | ----|------ 56 | user_id|user_id作为终端用户的唯一标识,确定用户的唯一性;作用于提供进阶数据分析服务,可在api1 或 api2 接口传入,不传入也不影响验证服务的使用;若担心用户信息风险,可作预处理(如哈希处理)再提供到极验 ; 57 | client_type|客户端类型,**web**(pc浏览器),**h5**(手机浏览器,包括webview),**native**(原生app),**unknown**(未知) 58 | ip_address|客户端请求您服务器的ip地址,**unknow**表示未知 59 | 60 | # 运行 demo 61 | 62 | > 您也许需要使用`sudo`命令才能执行下列命令 63 | 64 | ### Flask demo 运行 65 | 66 | >命令行进入flask_demo文件夹路径,执行命令: 67 | 68 | ``` 69 | $ python3 start.py 70 | ``` 71 | 72 | 在浏览器中访问`http://localhost:5000`即可看到demo界面。 73 | 74 | ### Tornado demo运行 75 | 76 | > 命令行进入tornado_demo文件夹路径,执行命令: 77 | 78 | ``` 79 | $ python3 start.py 80 | ``` 81 | 82 | 在浏览器中访问`http://localhost:8088`即可看到demo界面 83 | 84 | ### Django demo运行 85 | 86 | > 命令行进入django_demo文件夹路径,执行命令: 87 | 88 | ``` 89 | $ python3 manage.py runserver 0.0.0.0:8000 90 | ``` 91 | 92 | 在浏览器中访问`http://localhost:8000`即可看到demo界面 93 | 94 | 95 | 发布日志 96 | ----------------- 97 | + 3.4.0 98 | 99 | - 优化包结构 100 | - 整理代码失效链接 101 | - 升级新版failback表现形式 102 | 103 | + 3.3.2 104 | 105 | - 去掉代码和文档中的已失效的链接 106 | 107 | + 3.3.1 108 | 109 | - 保持 sdk 包名和导入名保持一致, geetest. 110 | 111 | + 3.3.0 112 | 113 | - 保持 sdk 包名和导入名保持一致, geetest. 114 | 115 | + 3.2.0 116 | 117 | - 添加用户标识(user_id)的接口 118 | 119 | + 3.1.2 120 | 121 | - 支持Python3 122 | 123 | + 3.1.1 124 | 125 | - 统一接口 126 | 127 | + 3.1.0 128 | 129 | - 添加challenge加密特性,使验证更安全, 老版本更新请先联系管理员 130 | 131 | + 3.0.1 132 | 133 | - 修复failback情况下 无法正确解码答案的错误 134 | 135 | + 3.0.0 136 | 137 | - 去除SDK对Session操作, 现在Session部分由开发者自己处理 138 | - 简易化初始化过程. 139 | - 修复failback模式BUG -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Gt3 Python SDK 2 | =============== 3 | 4 | 极验验证的Python SDK目前提供基于django, flask, tornado框架的DEMO。 5 | 6 | 7 | 开发环境 8 | ---------------- 9 | 10 | - Python (推荐3.5) 11 | - django, flask, tornado框架 12 | 13 | 快速开始 14 | --------------- 15 | 16 | 下面使用示例代码的均以flask框架为例。 17 | 18 | 1. 获取代码 19 | 20 | 从 `Github `__ 上Clone代码: 21 | 22 | .. code-block:: bash 23 | 24 | $ git clone https://github.com/GeeTeam/gt3-python-sdk.git 25 | 26 | 2. 安装pip依赖 27 | 28 | .. code-block:: bash 29 | 30 | $ sudo pip3 install -r requirements.txt 31 | 32 | 3. 初始化验证 33 | 34 | 35 | 在调用GeetestLib前请自行设定公钥和私钥,用户id为可选项,默认为随机数字: 36 | 37 | .. code-block :: python 38 | 39 | captach_id = "你的公钥" 40 | private_key = "你的私钥" 41 | user_id = random.randint(1,100) 42 | 43 | 根据自己的私钥初始化验证 44 | 45 | .. code-block :: python 46 | 47 | @app.route('/getcaptcha', methods=["GET"]) 48 | def get_captcha(): 49 | user_id = random.randint(1,100) 50 | gt = GeetestLib(captcha_id, private_key) 51 | status = gt.pre_process(user_id) 52 | session[gt.GT_STATUS_SESSION_KEY] = status 53 | session["user_id"] = user_id 54 | response_str = gt.get_response_str() 55 | return response_str 56 | 57 | 4. 二次验证 58 | 59 | .. code-block :: python 60 | 61 | @app.route('/validate', methods=["POST"]) 62 | def validate_capthca(): 63 | gt = GeetestLib(captcha_id, private_key) 64 | status = session[gt.GT_STATUS_SESSION_KEY] 65 | challenge = request.form[gt.FN_CHALLENGE] 66 | validate = request.form[gt.FN_VALIDATE] 67 | seccode = request.form[gt.FN_SECCODE] 68 | user_id = session["user_id"] 69 | if status: 70 | result = gt.success_validate(challenge, validate, seccode, user_id) 71 | else: 72 | result = gt.fail_validate(challenge, validate, seccode) 73 | result = "success" if result else "fail" 74 | return result 75 | 76 | 77 | 运行demo 78 | --------------------- 79 | 80 | 1. django demo运行:进入django_demo文件夹,运行: 81 | 82 | .. code-block:: bash 83 | 84 | $ python manage.py runserver 0.0.0.0:8000 85 | 86 | 在浏览器中访问http://localhost:8000即可看到Demo界面 87 | 88 | 2. flask demo运行:进入flask_demo文件夹,运行: 89 | 90 | .. code-block:: bash 91 | 92 | $ python start.py 93 | 94 | 在浏览器中访问http://localhost:5000即可看到Demo界面 95 | 96 | 3. tornado demo运行:进入tornado_demo文件夹,运行: 97 | 98 | .. code-block:: bash 99 | 100 | $ python start.py 101 | 102 | 在浏览器中访问http://localhost:8088即可看到Demo界面 103 | 104 | 105 | 发布日志 106 | ----------------- 107 | + 3.3.2 108 | 109 | - 去掉代码和文档中的已失效的链接 110 | 111 | + 3.3.1 112 | 113 | - 保持 sdk 包名和导入名保持一致, geetest. 114 | 115 | + 3.3.0 116 | 117 | - 保持 sdk 包名和导入名保持一致, geetest. 118 | 119 | + 3.2.0 120 | 121 | - 添加用户标识(user_id)的接口 122 | 123 | + 3.1.2 124 | 125 | - 支持Python3 126 | 127 | + 3.1.1 128 | 129 | - 统一接口 130 | 131 | + 3.1.0 132 | 133 | - 添加challenge加密特性,使验证更安全, 老版本更新请先联系管理员 134 | 135 | + 3.0.1 136 | 137 | - 修复failback情况下 无法正确解码答案的错误 138 | 139 | + 3.0.0 140 | 141 | - 去除SDK对Session操作, 现在Session部分由开发者自己处理 142 | - 简易化初始化过程. 143 | - 修复failback模式BUG 144 | -------------------------------------------------------------------------------- /demo/django_demo/app/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GeeTeam/gt3-python-sdk/afde6d6bdd15145e97579119495ca2cc82634963/demo/django_demo/app/__init__.py -------------------------------------------------------------------------------- /demo/django_demo/app/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GeeTeam/gt3-python-sdk/afde6d6bdd15145e97579119495ca2cc82634963/demo/django_demo/app/__init__.pyc -------------------------------------------------------------------------------- /demo/django_demo/app/views.py: -------------------------------------------------------------------------------- 1 | import json 2 | from django.http import HttpResponse 3 | from django.shortcuts import render_to_response, RequestContext 4 | 5 | from geetest import GeetestLib 6 | 7 | # 请在官网申请ID使用,示例ID不可使用 8 | pc_geetest_id = "b46d1900d0a894591916ea94ea91bd2c" 9 | pc_geetest_key = "36fc3fe98530eea08dfc6ce76e3d24c4" 10 | mobile_geetest_id = "7c25da6fe21944cfe507d2f9876775a9" 11 | mobile_geetest_key = "f5883f4ee3bd4fa8caec67941de1b903" 12 | 13 | 14 | def home(request): 15 | return render_to_response("index.html", context_instance=RequestContext(request)) 16 | 17 | 18 | def pcgetcaptcha(request): 19 | user_id = 'test' 20 | gt = GeetestLib(pc_geetest_id, pc_geetest_key) 21 | status = gt.pre_process(user_id) 22 | request.session[gt.GT_STATUS_SESSION_KEY] = status 23 | request.session["user_id"] = user_id 24 | response_str = gt.get_response_str() 25 | return HttpResponse(response_str) 26 | 27 | 28 | def mobilegetcaptcha(request): 29 | user_id = 'test' 30 | gt = GeetestLib(mobile_geetest_id, mobile_geetest_key) 31 | status = gt.pre_process(user_id) 32 | request.session[gt.GT_STATUS_SESSION_KEY] = status 33 | request.session["user_id"] = user_id 34 | response_str = gt.get_response_str() 35 | return HttpResponse(response_str) 36 | 37 | 38 | def pcvalidate(request): 39 | if request.method == "POST": 40 | gt = GeetestLib(pc_geetest_id, pc_geetest_key) 41 | challenge = request.POST.get(gt.FN_CHALLENGE, '') 42 | validate = request.POST.get(gt.FN_VALIDATE, '') 43 | seccode = request.POST.get(gt.FN_SECCODE, '') 44 | status = request.session[gt.GT_STATUS_SESSION_KEY] 45 | user_id = request.session["user_id"] 46 | if status: 47 | result = gt.success_validate(challenge, validate, seccode, user_id) 48 | else: 49 | result = gt.failback_validate(challenge, validate, seccode) 50 | result = "

登录成功

" if result else "

登录失败

" 51 | return HttpResponse(result) 52 | return HttpResponse("error") 53 | 54 | 55 | def pcajax_validate(request): 56 | if request.method == "POST": 57 | gt = GeetestLib(pc_geetest_id, pc_geetest_key) 58 | challenge = request.POST.get(gt.FN_CHALLENGE, '') 59 | validate = request.POST.get(gt.FN_VALIDATE, '') 60 | seccode = request.POST.get(gt.FN_SECCODE, '') 61 | status = request.session[gt.GT_STATUS_SESSION_KEY] 62 | user_id = request.session["user_id"] 63 | if status: 64 | result = gt.success_validate(challenge, validate, seccode, user_id) 65 | else: 66 | result = gt.failback_validate(challenge, validate, seccode) 67 | result = {"status": "success"} if result else {"status": "fail"} 68 | return HttpResponse(json.dumps(result)) 69 | return HttpResponse("error") 70 | 71 | 72 | def mobileajax_validate(request): 73 | if request.method == "POST": 74 | gt = GeetestLib(mobile_geetest_id, mobile_geetest_key) 75 | challenge = request.POST.get(gt.FN_CHALLENGE, '') 76 | validate = request.POST.get(gt.FN_VALIDATE, '') 77 | seccode = request.POST.get(gt.FN_SECCODE, '') 78 | status = request.session[gt.GT_STATUS_SESSION_KEY] 79 | user_id = request.session["user_id"] 80 | if status: 81 | result = gt.success_validate(challenge, validate, seccode, user_id) 82 | else: 83 | result = gt.failback_validate(challenge, validate, seccode) 84 | result = {"status": "success"} if result else {"status": "fail"} 85 | return HttpResponse(json.dumps(result)) 86 | return HttpResponse("error") 87 | -------------------------------------------------------------------------------- /demo/django_demo/db.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GeeTeam/gt3-python-sdk/afde6d6bdd15145e97579119495ca2cc82634963/demo/django_demo/db.sqlite3 -------------------------------------------------------------------------------- /demo/django_demo/django_demo/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GeeTeam/gt3-python-sdk/afde6d6bdd15145e97579119495ca2cc82634963/demo/django_demo/django_demo/__init__.py -------------------------------------------------------------------------------- /demo/django_demo/django_demo/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GeeTeam/gt3-python-sdk/afde6d6bdd15145e97579119495ca2cc82634963/demo/django_demo/django_demo/__init__.pyc -------------------------------------------------------------------------------- /demo/django_demo/django_demo/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for django_demo project. 3 | 4 | For more information on this file, see 5 | https://docs.djangoproject.com/en/1.7/topics/settings/ 6 | 7 | For the full list of settings and their values, see 8 | https://docs.djangoproject.com/en/1.7/ref/settings/ 9 | """ 10 | 11 | import os 12 | 13 | BASE_DIR = os.path.dirname(os.path.dirname(__file__)) 14 | 15 | # SECURITY WARNING: keep the secret key used in production secret! 16 | SECRET_KEY = 'g-^epx6*uxh!mv6#fwdy9m(xi2-+a*3g2wi73fuevua$m00_3o' 17 | 18 | DEBUG = True 19 | 20 | TEMPLATE_DEBUG = True 21 | 22 | ALLOWED_HOSTS = [] 23 | 24 | INSTALLED_APPS = ( 25 | 'django.contrib.admin', 26 | 'django.contrib.auth', 27 | 'django.contrib.contenttypes', 28 | 'django.contrib.sessions', 29 | 'django.contrib.messages', 30 | 'django.contrib.staticfiles', 31 | 'app', 32 | ) 33 | 34 | MIDDLEWARE_CLASSES = ( 35 | 'django.contrib.sessions.middleware.SessionMiddleware', 36 | 'django.middleware.common.CommonMiddleware', 37 | # 'django.middleware.csrf.CsrfViewMiddleware', 38 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 39 | 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 40 | 'django.contrib.messages.middleware.MessageMiddleware', 41 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 42 | ) 43 | 44 | ROOT_URLCONF = 'django_demo.urls' 45 | 46 | WSGI_APPLICATION = 'django_demo.wsgi.application' 47 | 48 | DATABASES = { 49 | 'default': { 50 | 'ENGINE': 'django.db.backends.sqlite3', 51 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 52 | } 53 | } 54 | 55 | LANGUAGE_CODE = 'en-us' 56 | 57 | TIME_ZONE = 'UTC' 58 | 59 | USE_I18N = True 60 | 61 | USE_L10N = True 62 | 63 | USE_TZ = True 64 | 65 | STATIC_URL = '/static/' 66 | 67 | TEMPLATE_DIRS = ( 68 | "static", 69 | ) 70 | STATICFILES_DIRS = [ 71 | os.path.join(BASE_DIR, 'static') 72 | ] 73 | -------------------------------------------------------------------------------- /demo/django_demo/django_demo/settings.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GeeTeam/gt3-python-sdk/afde6d6bdd15145e97579119495ca2cc82634963/demo/django_demo/django_demo/settings.pyc -------------------------------------------------------------------------------- /demo/django_demo/django_demo/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | 3 | urlpatterns = [ 4 | url(r'^pc-geetest/register', 'app.views.pcgetcaptcha', name='pcgetcaptcha'), 5 | url(r'^mobile-geetest/register', 'app.views.mobilegetcaptcha', name='mobilegetcaptcha'), 6 | url(r'^pc-geetest/validate$', 'app.views.pcvalidate', name='pcvalidate'), 7 | url(r'^pc-geetest/ajax_validate', 'app.views.pcajax_validate', name='pcajax_validate'), 8 | url(r'^mobile-geetest/ajax_validate', 'app.views.mobileajax_validate', name='mobileajax_validate'), 9 | url(r'/*', 'app.views.home', name='home'), 10 | ] 11 | -------------------------------------------------------------------------------- /demo/django_demo/django_demo/urls.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GeeTeam/gt3-python-sdk/afde6d6bdd15145e97579119495ca2cc82634963/demo/django_demo/django_demo/urls.pyc -------------------------------------------------------------------------------- /demo/django_demo/django_demo/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for django_demo project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_demo.settings") 12 | 13 | from django.core.wsgi import get_wsgi_application 14 | application = get_wsgi_application() 15 | -------------------------------------------------------------------------------- /demo/django_demo/geetest/__init__.py: -------------------------------------------------------------------------------- 1 | from .geetest import GeetestLib, VERSION -------------------------------------------------------------------------------- /demo/django_demo/geetest/geetest.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import random 3 | import json 4 | import requests 5 | import time 6 | from hashlib import md5 7 | 8 | if sys.version_info >= (3,): 9 | xrange = range 10 | 11 | VERSION = "3.0.0" 12 | 13 | 14 | class GeetestLib(object): 15 | FN_CHALLENGE = "geetest_challenge" 16 | FN_VALIDATE = "geetest_validate" 17 | FN_SECCODE = "geetest_seccode" 18 | 19 | GT_STATUS_SESSION_KEY = "gt_server_status" 20 | 21 | API_URL = "http://api.geetest.com" 22 | REGISTER_HANDLER = "/register.php" 23 | VALIDATE_HANDLER = "/validate.php" 24 | JSON_FORMAT = False 25 | 26 | def __init__(self, captcha_id, private_key): 27 | self.private_key = private_key 28 | self.captcha_id = captcha_id 29 | self.sdk_version = VERSION 30 | self._response_str = "" 31 | 32 | def pre_process(self, user_id=None, new_captcha=1, JSON_FORMAT=1, client_type="web", ip_address=""): 33 | status, challenge = self._register(user_id, new_captcha, JSON_FORMAT, client_type, ip_address) 34 | self._response_str = self._make_response_format(status, challenge, new_captcha) 35 | return status 36 | 37 | def _register(self, user_id=None, new_captcha=1, JSON_FORMAT=1, client_type="web", ip_address=""): 38 | pri_responce = self._register_challenge(user_id, new_captcha, JSON_FORMAT, client_type, ip_address) 39 | if pri_responce: 40 | if JSON_FORMAT == 1: 41 | response_dic = json.loads(pri_responce) 42 | challenge = response_dic["challenge"] 43 | else: 44 | challenge = pri_responce 45 | else: 46 | challenge = " " 47 | if len(challenge) == 32: 48 | challenge = self._md5_encode("".join([challenge, self.private_key])) 49 | return 1, challenge 50 | else: 51 | return 0, self._make_fail_challenge() 52 | 53 | def get_response_str(self): 54 | return self._response_str 55 | 56 | def _make_fail_challenge(self): 57 | rnd1 = random.randint(0, 99) 58 | rnd2 = random.randint(0, 99) 59 | md5_str1 = self._md5_encode(str(rnd1)) 60 | md5_str2 = self._md5_encode(str(rnd2)) 61 | challenge = md5_str1 + md5_str2[0:2] 62 | return challenge 63 | 64 | def _make_response_format(self, success=1, challenge=None, new_captcha=1): 65 | if not challenge: 66 | challenge = self._make_fail_challenge() 67 | if new_captcha: 68 | string_format = json.dumps( 69 | {'success': success, 'gt': self.captcha_id, 'challenge': challenge, "new_captcha": True}) 70 | else: 71 | string_format = json.dumps( 72 | {'success': success, 'gt': self.captcha_id, 'challenge': challenge, "new_captcha": False}) 73 | return string_format 74 | 75 | def _register_challenge(self, user_id=None, new_captcha=1, JSON_FORMAT=1, client_type="web", ip_address=""): 76 | if user_id: 77 | 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( 78 | api_url=self.API_URL, handler=self.REGISTER_HANDLER, captcha_ID=self.captcha_id, user_id=user_id, 79 | new_captcha=new_captcha, JSON_FORMAT=JSON_FORMAT, client_type=client_type, ip_address=ip_address) 80 | else: 81 | register_url = "{api_url}{handler}?gt={captcha_ID}&json_format={JSON_FORMAT}&client_type={client_type}&ip_address={ip_address}".format( 82 | api_url=self.API_URL, handler=self.REGISTER_HANDLER, captcha_ID=self.captcha_id, 83 | new_captcha=new_captcha, JSON_FORMAT=JSON_FORMAT, client_type=client_type, ip_address=ip_address) 84 | try: 85 | response = requests.get(register_url, timeout=2) 86 | if response.status_code == requests.codes.ok: 87 | res_string = response.text 88 | else: 89 | res_string = "" 90 | except: 91 | res_string = "" 92 | return res_string 93 | 94 | def success_validate(self, challenge, validate, seccode, user_id=None, gt=None, data='', userinfo='', 95 | JSON_FORMAT=1): 96 | """ 97 | 正常模式的二次验证方式.向geetest server 请求验证结果. 98 | """ 99 | if not self._check_para(challenge, validate, seccode): 100 | return 0 101 | if not self._check_result(challenge, validate): 102 | return 0 103 | validate_url = "{api_url}{handler}".format( 104 | api_url=self.API_URL, handler=self.VALIDATE_HANDLER) 105 | query = { 106 | "seccode": seccode, 107 | "sdk": ''.join(["python_", self.sdk_version]), 108 | "user_id": user_id, 109 | "data": data, 110 | "timestamp": time.time(), 111 | "challenge": challenge, 112 | "userinfo": userinfo, 113 | "captchaid": gt, 114 | "json_format": JSON_FORMAT 115 | } 116 | backinfo = self._post_values(validate_url, query) 117 | if JSON_FORMAT == 1: 118 | backinfo = json.loads(backinfo) 119 | backinfo = backinfo["seccode"] 120 | if backinfo == self._md5_encode(seccode): 121 | return 1 122 | else: 123 | return 0 124 | 125 | def _post_values(self, apiserver, data): 126 | response = requests.post(apiserver, data) 127 | return response.text 128 | 129 | def _check_result(self, origin, validate): 130 | encodeStr = self._md5_encode(self.private_key + "geetest" + origin) 131 | if validate == encodeStr: 132 | return True 133 | else: 134 | return False 135 | 136 | def failback_validate(self, challenge, validate, seccode): 137 | """ 138 | failback模式的二次验证方式.在本地对轨迹进行简单的判断返回验证结果. 139 | """ 140 | if not self._check_para(challenge, validate, seccode): 141 | return 0 142 | validate_result = self._failback_check_result( 143 | challenge, validate, ) 144 | return validate_result 145 | 146 | def _failback_check_result(self, challenge, validate): 147 | encodeStr = self._md5_encode(challenge) 148 | if validate == encodeStr: 149 | return True 150 | else: 151 | return False 152 | 153 | def _check_para(self, challenge, validate, seccode): 154 | return (bool(challenge.strip()) and bool(validate.strip()) and bool(seccode.strip())) 155 | 156 | def _md5_encode(self, values): 157 | if type(values) == str: 158 | values = values.encode() 159 | m = md5(values) 160 | return m.hexdigest() 161 | -------------------------------------------------------------------------------- /demo/django_demo/manage.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | if __name__ == "__main__": 5 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_demo.settings") 6 | 7 | from django.core.management import execute_from_command_line 8 | 9 | execute_from_command_line(sys.argv) 10 | -------------------------------------------------------------------------------- /demo/django_demo/requirements.txt: -------------------------------------------------------------------------------- 1 | certifi==2017.7.27.1 2 | chardet==3.0.4 3 | Django==1.8 4 | idna==2.6 5 | pytz==2017.3 6 | requests==2.18.4 7 | urllib3==1.22 8 | -------------------------------------------------------------------------------- /demo/django_demo/static/gt.js: -------------------------------------------------------------------------------- 1 | "v0.4.8 Geetest Inc."; 2 | 3 | (function (window) { 4 | "use strict"; 5 | if (typeof window === 'undefined') { 6 | throw new Error('Geetest requires browser environment'); 7 | } 8 | 9 | var document = window.document; 10 | var Math = window.Math; 11 | var head = document.getElementsByTagName("head")[0]; 12 | 13 | function _Object(obj) { 14 | this._obj = obj; 15 | } 16 | 17 | _Object.prototype = { 18 | _each: function (process) { 19 | var _obj = this._obj; 20 | for (var k in _obj) { 21 | if (_obj.hasOwnProperty(k)) { 22 | process(k, _obj[k]); 23 | } 24 | } 25 | return this; 26 | } 27 | }; 28 | 29 | function Config(config) { 30 | var self = this; 31 | new _Object(config)._each(function (key, value) { 32 | self[key] = value; 33 | }); 34 | } 35 | 36 | Config.prototype = { 37 | api_server: 'api.geetest.com', 38 | protocol: 'http://', 39 | typePath: '/gettype.php', 40 | fallback_config: { 41 | slide: { 42 | static_servers: ["static.geetest.com", "dn-staticdown.qbox.me"], 43 | type: 'slide', 44 | slide: '/static/js/geetest.0.0.0.js' 45 | }, 46 | fullpage: { 47 | static_servers: ["static.geetest.com", "dn-staticdown.qbox.me"], 48 | type: 'fullpage', 49 | fullpage: '/static/js/fullpage.0.0.0.js' 50 | } 51 | }, 52 | _get_fallback_config: function () { 53 | var self = this; 54 | if (isString(self.type)) { 55 | return self.fallback_config[self.type]; 56 | } else if (self.new_captcha) { 57 | return self.fallback_config.fullpage; 58 | } else { 59 | return self.fallback_config.slide; 60 | } 61 | }, 62 | _extend: function (obj) { 63 | var self = this; 64 | new _Object(obj)._each(function (key, value) { 65 | self[key] = value; 66 | }) 67 | } 68 | }; 69 | var isNumber = function (value) { 70 | return (typeof value === 'number'); 71 | }; 72 | var isString = function (value) { 73 | return (typeof value === 'string'); 74 | }; 75 | var isBoolean = function (value) { 76 | return (typeof value === 'boolean'); 77 | }; 78 | var isObject = function (value) { 79 | return (typeof value === 'object' && value !== null); 80 | }; 81 | var isFunction = function (value) { 82 | return (typeof value === 'function'); 83 | }; 84 | var MOBILE = /Mobi/i.test(navigator.userAgent); 85 | var pt = MOBILE ? 3 : 0; 86 | 87 | var callbacks = {}; 88 | var status = {}; 89 | 90 | var nowDate = function () { 91 | var date = new Date(); 92 | var year = date.getFullYear(); 93 | var month = date.getMonth() + 1; 94 | var day = date.getDate(); 95 | var hours = date.getHours(); 96 | var minutes = date.getMinutes(); 97 | var seconds = date.getSeconds(); 98 | 99 | if (month >= 1 && month <= 9) { 100 | month = '0' + month; 101 | } 102 | if (day >= 0 && day <= 9) { 103 | day = '0' + day; 104 | } 105 | if (hours >= 0 && hours <= 9) { 106 | hours = '0' + hours; 107 | } 108 | if (minutes >= 0 && minutes <= 9) { 109 | minutes = '0' + minutes; 110 | } 111 | if (seconds >= 0 && seconds <= 9) { 112 | seconds = '0' + seconds; 113 | } 114 | var currentdate = year + '-' + month + '-' + day + " " + hours + ":" + minutes + ":" + seconds; 115 | return currentdate; 116 | } 117 | 118 | var random = function () { 119 | return parseInt(Math.random() * 10000) + (new Date()).valueOf(); 120 | }; 121 | 122 | var loadScript = function (url, cb) { 123 | var script = document.createElement("script"); 124 | script.charset = "UTF-8"; 125 | script.async = true; 126 | 127 | // 对geetest的静态资源添加 crossOrigin 128 | if ( /static\.geetest\.com/g.test(url)) { 129 | script.crossOrigin = "anonymous"; 130 | } 131 | 132 | script.onerror = function () { 133 | cb(true); 134 | }; 135 | var loaded = false; 136 | script.onload = script.onreadystatechange = function () { 137 | if (!loaded && 138 | (!script.readyState || 139 | "loaded" === script.readyState || 140 | "complete" === script.readyState)) { 141 | 142 | loaded = true; 143 | setTimeout(function () { 144 | cb(false); 145 | }, 0); 146 | } 147 | }; 148 | script.src = url; 149 | head.appendChild(script); 150 | }; 151 | 152 | var normalizeDomain = function (domain) { 153 | // special domain: uems.sysu.edu.cn/jwxt/geetest/ 154 | // return domain.replace(/^https?:\/\/|\/.*$/g, ''); uems.sysu.edu.cn 155 | return domain.replace(/^https?:\/\/|\/$/g, ''); // uems.sysu.edu.cn/jwxt/geetest 156 | }; 157 | var normalizePath = function (path) { 158 | path = path.replace(/\/+/g, '/'); 159 | if (path.indexOf('/') !== 0) { 160 | path = '/' + path; 161 | } 162 | return path; 163 | }; 164 | var normalizeQuery = function (query) { 165 | if (!query) { 166 | return ''; 167 | } 168 | var q = '?'; 169 | new _Object(query)._each(function (key, value) { 170 | if (isString(value) || isNumber(value) || isBoolean(value)) { 171 | q = q + encodeURIComponent(key) + '=' + encodeURIComponent(value) + '&'; 172 | } 173 | }); 174 | if (q === '?') { 175 | q = ''; 176 | } 177 | return q.replace(/&$/, ''); 178 | }; 179 | var makeURL = function (protocol, domain, path, query) { 180 | domain = normalizeDomain(domain); 181 | 182 | var url = normalizePath(path) + normalizeQuery(query); 183 | if (domain) { 184 | url = protocol + domain + url; 185 | } 186 | 187 | return url; 188 | }; 189 | 190 | var load = function (config, send, protocol, domains, path, query, cb) { 191 | var tryRequest = function (at) { 192 | 193 | var url = makeURL(protocol, domains[at], path, query); 194 | loadScript(url, function (err) { 195 | if (err) { 196 | if (at >= domains.length - 1) { 197 | cb(true); 198 | // report gettype error 199 | if (send) { 200 | config.error_code = 508; 201 | var url = protocol + domains[at] + path; 202 | reportError(config, url); 203 | } 204 | } else { 205 | tryRequest(at + 1); 206 | } 207 | } else { 208 | cb(false); 209 | } 210 | }); 211 | }; 212 | tryRequest(0); 213 | }; 214 | 215 | 216 | var jsonp = function (domains, path, config, callback) { 217 | if (isObject(config.getLib)) { 218 | config._extend(config.getLib); 219 | callback(config); 220 | return; 221 | } 222 | if (config.offline) { 223 | callback(config._get_fallback_config()); 224 | return; 225 | } 226 | 227 | var cb = "geetest_" + random(); 228 | window[cb] = function (data) { 229 | if (data.status == 'success') { 230 | callback(data.data); 231 | } else if (!data.status) { 232 | callback(data); 233 | } else { 234 | callback(config._get_fallback_config()); 235 | } 236 | window[cb] = undefined; 237 | try { 238 | delete window[cb]; 239 | } catch (e) { 240 | } 241 | }; 242 | load(config, true, config.protocol, domains, path, { 243 | gt: config.gt, 244 | callback: cb 245 | }, function (err) { 246 | if (err) { 247 | callback(config._get_fallback_config()); 248 | } 249 | }); 250 | }; 251 | 252 | var reportError = function (config, url) { 253 | load(config, false, config.protocol, ['monitor.geetest.com'], '/monitor/send', { 254 | time: nowDate(), 255 | captcha_id: config.gt, 256 | challenge: config.challenge, 257 | pt: pt, 258 | exception_url: url, 259 | error_code: config.error_code 260 | }, function (err) {}) 261 | } 262 | 263 | var throwError = function (errorType, config) { 264 | var errors = { 265 | networkError: '网络错误', 266 | gtTypeError: 'gt字段不是字符串类型' 267 | }; 268 | if (typeof config.onError === 'function') { 269 | config.onError(errors[errorType]); 270 | } else { 271 | throw new Error(errors[errorType]); 272 | } 273 | }; 274 | 275 | var detect = function () { 276 | return window.Geetest || document.getElementById("gt_lib"); 277 | }; 278 | 279 | if (detect()) { 280 | status.slide = "loaded"; 281 | } 282 | 283 | window.initGeetest = function (userConfig, callback) { 284 | 285 | var config = new Config(userConfig); 286 | 287 | if (userConfig.https) { 288 | config.protocol = 'https://'; 289 | } else if (!userConfig.protocol) { 290 | config.protocol = window.location.protocol + '//'; 291 | } 292 | 293 | // for KFC 294 | if (userConfig.gt === '050cffef4ae57b5d5e529fea9540b0d1' || 295 | userConfig.gt === '3bd38408ae4af923ed36e13819b14d42') { 296 | config.apiserver = 'yumchina.geetest.com/'; // for old js 297 | config.api_server = 'yumchina.geetest.com'; 298 | } 299 | 300 | if(userConfig.gt){ 301 | window.GeeGT = userConfig.gt 302 | } 303 | 304 | if(userConfig.challenge){ 305 | window.GeeChallenge = userConfig.challenge 306 | } 307 | 308 | if (isObject(userConfig.getType)) { 309 | config._extend(userConfig.getType); 310 | } 311 | jsonp([config.api_server || config.apiserver], config.typePath, config, function (newConfig) { 312 | var type = newConfig.type; 313 | var init = function () { 314 | config._extend(newConfig); 315 | callback(new window.Geetest(config)); 316 | }; 317 | 318 | callbacks[type] = callbacks[type] || []; 319 | var s = status[type] || 'init'; 320 | if (s === 'init') { 321 | status[type] = 'loading'; 322 | 323 | callbacks[type].push(init); 324 | 325 | load(config, true, config.protocol, newConfig.static_servers || newConfig.domains, newConfig[type] || newConfig.path, null, function (err) { 326 | if (err) { 327 | status[type] = 'fail'; 328 | throwError('networkError', config); 329 | } else { 330 | status[type] = 'loaded'; 331 | var cbs = callbacks[type]; 332 | for (var i = 0, len = cbs.length; i < len; i = i + 1) { 333 | var cb = cbs[i]; 334 | if (isFunction(cb)) { 335 | cb(); 336 | } 337 | } 338 | callbacks[type] = []; 339 | } 340 | }); 341 | } else if (s === "loaded") { 342 | init(); 343 | } else if (s === "fail") { 344 | throwError('networkError', config); 345 | } else if (s === "loading") { 346 | callbacks[type].push(init); 347 | } 348 | }); 349 | 350 | }; 351 | 352 | 353 | })(window); 354 | 355 | -------------------------------------------------------------------------------- /demo/django_demo/static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | gt-python-django-demo 7 | 74 | 75 | 76 |

极验验证SDKDemo

77 |

78 |
79 |

80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 108 | 109 | 158 |

159 |
160 |

161 | 181 | 182 | 219 |

220 |
221 |

222 | 239 | 240 | 294 | 295 | 296 | 297 | -------------------------------------------------------------------------------- /demo/flask_demo/geetest/__init__.py: -------------------------------------------------------------------------------- 1 | from .geetest import GeetestLib, VERSION -------------------------------------------------------------------------------- /demo/flask_demo/geetest/geetest.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import random 3 | import json 4 | import requests 5 | import time 6 | from hashlib import md5 7 | 8 | if sys.version_info >= (3,): 9 | xrange = range 10 | 11 | VERSION = "3.0.0" 12 | 13 | 14 | class GeetestLib(object): 15 | FN_CHALLENGE = "geetest_challenge" 16 | FN_VALIDATE = "geetest_validate" 17 | FN_SECCODE = "geetest_seccode" 18 | 19 | GT_STATUS_SESSION_KEY = "gt_server_status" 20 | 21 | API_URL = "http://api.geetest.com" 22 | REGISTER_HANDLER = "/register.php" 23 | VALIDATE_HANDLER = "/validate.php" 24 | JSON_FORMAT = False 25 | 26 | def __init__(self, captcha_id, private_key): 27 | self.private_key = private_key 28 | self.captcha_id = captcha_id 29 | self.sdk_version = VERSION 30 | self._response_str = "" 31 | 32 | def pre_process(self, user_id=None, new_captcha=1, JSON_FORMAT=1, client_type="web", ip_address=""): 33 | status, challenge = self._register(user_id, new_captcha, JSON_FORMAT, client_type, ip_address) 34 | self._response_str = self._make_response_format(status, challenge, new_captcha) 35 | return status 36 | 37 | def _register(self, user_id=None, new_captcha=1, JSON_FORMAT=1, client_type="web", ip_address=""): 38 | pri_responce = self._register_challenge(user_id, new_captcha, JSON_FORMAT, client_type, ip_address) 39 | if pri_responce: 40 | if JSON_FORMAT == 1: 41 | response_dic = json.loads(pri_responce) 42 | challenge = response_dic["challenge"] 43 | else: 44 | challenge = pri_responce 45 | else: 46 | challenge = " " 47 | if len(challenge) == 32: 48 | challenge = self._md5_encode("".join([challenge, self.private_key])) 49 | return 1, challenge 50 | else: 51 | return 0, self._make_fail_challenge() 52 | 53 | def get_response_str(self): 54 | return self._response_str 55 | 56 | def _make_fail_challenge(self): 57 | rnd1 = random.randint(0, 99) 58 | rnd2 = random.randint(0, 99) 59 | md5_str1 = self._md5_encode(str(rnd1)) 60 | md5_str2 = self._md5_encode(str(rnd2)) 61 | challenge = md5_str1 + md5_str2[0:2] 62 | return challenge 63 | 64 | def _make_response_format(self, success=1, challenge=None, new_captcha=1): 65 | if not challenge: 66 | challenge = self._make_fail_challenge() 67 | if new_captcha: 68 | string_format = json.dumps( 69 | {'success': success, 'gt': self.captcha_id, 'challenge': challenge, "new_captcha": True}) 70 | else: 71 | string_format = json.dumps( 72 | {'success': success, 'gt': self.captcha_id, 'challenge': challenge, "new_captcha": False}) 73 | return string_format 74 | 75 | def _register_challenge(self, user_id=None, new_captcha=1, JSON_FORMAT=1, client_type="web", ip_address=""): 76 | if user_id: 77 | 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( 78 | api_url=self.API_URL, handler=self.REGISTER_HANDLER, captcha_ID=self.captcha_id, user_id=user_id, 79 | new_captcha=new_captcha, JSON_FORMAT=JSON_FORMAT, client_type=client_type, ip_address=ip_address) 80 | else: 81 | register_url = "{api_url}{handler}?gt={captcha_ID}&json_format={JSON_FORMAT}&client_type={client_type}&ip_address={ip_address}".format( 82 | api_url=self.API_URL, handler=self.REGISTER_HANDLER, captcha_ID=self.captcha_id, 83 | new_captcha=new_captcha, JSON_FORMAT=JSON_FORMAT, client_type=client_type, ip_address=ip_address) 84 | try: 85 | response = requests.get(register_url, timeout=2) 86 | if response.status_code == requests.codes.ok: 87 | res_string = response.text 88 | else: 89 | res_string = "" 90 | except: 91 | res_string = "" 92 | return res_string 93 | 94 | def success_validate(self, challenge, validate, seccode, user_id=None, gt=None, data='', userinfo='', 95 | JSON_FORMAT=1): 96 | """ 97 | 正常模式的二次验证方式.向geetest server 请求验证结果. 98 | """ 99 | if not self._check_para(challenge, validate, seccode): 100 | return 0 101 | if not self._check_result(challenge, validate): 102 | return 0 103 | validate_url = "{api_url}{handler}".format( 104 | api_url=self.API_URL, handler=self.VALIDATE_HANDLER) 105 | query = { 106 | "seccode": seccode, 107 | "sdk": ''.join(["python_", self.sdk_version]), 108 | "user_id": user_id, 109 | "data": data, 110 | "timestamp": time.time(), 111 | "challenge": challenge, 112 | "userinfo": userinfo, 113 | "captchaid": gt, 114 | "json_format": JSON_FORMAT 115 | } 116 | backinfo = self._post_values(validate_url, query) 117 | if JSON_FORMAT == 1: 118 | backinfo = json.loads(backinfo) 119 | backinfo = backinfo["seccode"] 120 | if backinfo == self._md5_encode(seccode): 121 | return 1 122 | else: 123 | return 0 124 | 125 | def _post_values(self, apiserver, data): 126 | response = requests.post(apiserver, data) 127 | return response.text 128 | 129 | def _check_result(self, origin, validate): 130 | encodeStr = self._md5_encode(self.private_key + "geetest" + origin) 131 | if validate == encodeStr: 132 | return True 133 | else: 134 | return False 135 | 136 | def failback_validate(self, challenge, validate, seccode): 137 | """ 138 | failback模式的二次验证方式.在本地对轨迹进行简单的判断返回验证结果. 139 | """ 140 | if not self._check_para(challenge, validate, seccode): 141 | return 0 142 | validate_result = self._failback_check_result( 143 | challenge, validate, ) 144 | return validate_result 145 | 146 | def _failback_check_result(self, challenge, validate): 147 | encodeStr = self._md5_encode(challenge) 148 | if validate == encodeStr: 149 | return True 150 | else: 151 | return False 152 | 153 | def _check_para(self, challenge, validate, seccode): 154 | return (bool(challenge.strip()) and bool(validate.strip()) and bool(seccode.strip())) 155 | 156 | def _md5_encode(self, values): 157 | if type(values) == str: 158 | values = values.encode() 159 | m = md5(values) 160 | return m.hexdigest() 161 | -------------------------------------------------------------------------------- /demo/flask_demo/requirements.txt: -------------------------------------------------------------------------------- 1 | flask 2 | requests -------------------------------------------------------------------------------- /demo/flask_demo/start.py: -------------------------------------------------------------------------------- 1 | import json 2 | from flask import session, make_response, Flask, request, render_template 3 | 4 | from geetest import GeetestLib 5 | 6 | # 请在官网申请ID使用,示例ID不可使用 7 | pc_geetest_id = "48a6ebac4ebc6642d68c217fca33eb4d" 8 | pc_geetest_key = "4f1c085290bec5afdc54df73535fc361" 9 | 10 | mobile_geetest_id = "48a6ebac4ebc6642d68c217fca33eb4d" 11 | mobile_geetest_key = "4f1c085290bec5afdc54df73535fc361" 12 | 13 | app = Flask(__name__) 14 | app.config.update( 15 | DEBUG=True, 16 | ) 17 | 18 | 19 | @app.route('/pc-geetest/register', methods=["GET"]) 20 | def get_pc_captcha(): 21 | user_id = 'test' 22 | gt = GeetestLib(pc_geetest_id, pc_geetest_key) 23 | status = gt.pre_process(user_id) 24 | session[gt.GT_STATUS_SESSION_KEY] = status 25 | session["user_id"] = user_id 26 | response_str = gt.get_response_str() 27 | return response_str 28 | 29 | 30 | @app.route('/mobile-geetest/register', methods=["GET"]) 31 | def get_mobile_captcha(): 32 | user_id = 'test' 33 | gt = GeetestLib(mobile_geetest_id, mobile_geetest_key) 34 | status = gt.pre_process(user_id) 35 | session[gt.GT_STATUS_SESSION_KEY] = status 36 | session["user_id"] = user_id 37 | response_str = gt.get_response_str() 38 | return response_str 39 | 40 | 41 | @app.route('/pc-geetest/validate', methods=["POST"]) 42 | def pc_validate_captcha(): 43 | gt = GeetestLib(pc_geetest_id, pc_geetest_key) 44 | challenge = request.form[gt.FN_CHALLENGE] 45 | validate = request.form[gt.FN_VALIDATE] 46 | seccode = request.form[gt.FN_SECCODE] 47 | status = session[gt.GT_STATUS_SESSION_KEY] 48 | user_id = session["user_id"] 49 | if status: 50 | result = gt.success_validate(challenge, validate, seccode, user_id) 51 | else: 52 | result = gt.failback_validate(challenge, validate, seccode) 53 | result = "

登录成功

" if result else "

登录失败

" 54 | return result 55 | 56 | 57 | @app.route('/pc-geetest/ajax_validate', methods=["POST"]) 58 | def pc_ajax_validate(): 59 | gt = GeetestLib(pc_geetest_id, pc_geetest_key) 60 | challenge = request.form[gt.FN_CHALLENGE] 61 | validate = request.form[gt.FN_VALIDATE] 62 | seccode = request.form[gt.FN_SECCODE] 63 | status = session[gt.GT_STATUS_SESSION_KEY] 64 | user_id = session["user_id"] 65 | if status: 66 | result = gt.success_validate(challenge, validate, seccode, user_id, data='', userinfo='') 67 | else: 68 | result = gt.failback_validate(challenge, validate, seccode) 69 | result = {"status": "success"} if result else {"status": "fail"} 70 | return json.dumps(result) 71 | 72 | 73 | @app.route('/mobile-geetest/ajax_validate', methods=["POST"]) 74 | def mobile_ajax_validate(): 75 | gt = GeetestLib(mobile_geetest_id, mobile_geetest_key) 76 | challenge = request.form[gt.FN_CHALLENGE] 77 | validate = request.form[gt.FN_VALIDATE] 78 | seccode = request.form[gt.FN_SECCODE] 79 | status = session[gt.GT_STATUS_SESSION_KEY] 80 | user_id = session["user_id"] 81 | if status: 82 | result = gt.success_validate(challenge, validate, seccode, user_id, data='', userinfo='') 83 | else: 84 | result = gt.failback_validate(challenge, validate, seccode) 85 | result = {"status": "success"} if result else {"status": "fail"} 86 | return json.dumps(result) 87 | 88 | 89 | @app.route('/') 90 | def login(): 91 | return render_template('login.html') 92 | 93 | 94 | if __name__ == '__main__': 95 | app.secret_key = 'i-like-python' 96 | app.run() 97 | -------------------------------------------------------------------------------- /demo/flask_demo/static/gt.js: -------------------------------------------------------------------------------- 1 | "v0.4.8 Geetest Inc."; 2 | 3 | (function (window) { 4 | "use strict"; 5 | if (typeof window === 'undefined') { 6 | throw new Error('Geetest requires browser environment'); 7 | } 8 | 9 | var document = window.document; 10 | var Math = window.Math; 11 | var head = document.getElementsByTagName("head")[0]; 12 | 13 | function _Object(obj) { 14 | this._obj = obj; 15 | } 16 | 17 | _Object.prototype = { 18 | _each: function (process) { 19 | var _obj = this._obj; 20 | for (var k in _obj) { 21 | if (_obj.hasOwnProperty(k)) { 22 | process(k, _obj[k]); 23 | } 24 | } 25 | return this; 26 | } 27 | }; 28 | 29 | function Config(config) { 30 | var self = this; 31 | new _Object(config)._each(function (key, value) { 32 | self[key] = value; 33 | }); 34 | } 35 | 36 | Config.prototype = { 37 | api_server: 'api.geetest.com', 38 | protocol: 'http://', 39 | typePath: '/gettype.php', 40 | fallback_config: { 41 | slide: { 42 | static_servers: ["static.geetest.com", "dn-staticdown.qbox.me"], 43 | type: 'slide', 44 | slide: '/static/js/geetest.0.0.0.js' 45 | }, 46 | fullpage: { 47 | static_servers: ["static.geetest.com", "dn-staticdown.qbox.me"], 48 | type: 'fullpage', 49 | fullpage: '/static/js/fullpage.0.0.0.js' 50 | } 51 | }, 52 | _get_fallback_config: function () { 53 | var self = this; 54 | if (isString(self.type)) { 55 | return self.fallback_config[self.type]; 56 | } else if (self.new_captcha) { 57 | return self.fallback_config.fullpage; 58 | } else { 59 | return self.fallback_config.slide; 60 | } 61 | }, 62 | _extend: function (obj) { 63 | var self = this; 64 | new _Object(obj)._each(function (key, value) { 65 | self[key] = value; 66 | }) 67 | } 68 | }; 69 | var isNumber = function (value) { 70 | return (typeof value === 'number'); 71 | }; 72 | var isString = function (value) { 73 | return (typeof value === 'string'); 74 | }; 75 | var isBoolean = function (value) { 76 | return (typeof value === 'boolean'); 77 | }; 78 | var isObject = function (value) { 79 | return (typeof value === 'object' && value !== null); 80 | }; 81 | var isFunction = function (value) { 82 | return (typeof value === 'function'); 83 | }; 84 | var MOBILE = /Mobi/i.test(navigator.userAgent); 85 | var pt = MOBILE ? 3 : 0; 86 | 87 | var callbacks = {}; 88 | var status = {}; 89 | 90 | var nowDate = function () { 91 | var date = new Date(); 92 | var year = date.getFullYear(); 93 | var month = date.getMonth() + 1; 94 | var day = date.getDate(); 95 | var hours = date.getHours(); 96 | var minutes = date.getMinutes(); 97 | var seconds = date.getSeconds(); 98 | 99 | if (month >= 1 && month <= 9) { 100 | month = '0' + month; 101 | } 102 | if (day >= 0 && day <= 9) { 103 | day = '0' + day; 104 | } 105 | if (hours >= 0 && hours <= 9) { 106 | hours = '0' + hours; 107 | } 108 | if (minutes >= 0 && minutes <= 9) { 109 | minutes = '0' + minutes; 110 | } 111 | if (seconds >= 0 && seconds <= 9) { 112 | seconds = '0' + seconds; 113 | } 114 | var currentdate = year + '-' + month + '-' + day + " " + hours + ":" + minutes + ":" + seconds; 115 | return currentdate; 116 | } 117 | 118 | var random = function () { 119 | return parseInt(Math.random() * 10000) + (new Date()).valueOf(); 120 | }; 121 | 122 | var loadScript = function (url, cb) { 123 | var script = document.createElement("script"); 124 | script.charset = "UTF-8"; 125 | script.async = true; 126 | 127 | // 对geetest的静态资源添加 crossOrigin 128 | if ( /static\.geetest\.com/g.test(url)) { 129 | script.crossOrigin = "anonymous"; 130 | } 131 | 132 | script.onerror = function () { 133 | cb(true); 134 | }; 135 | var loaded = false; 136 | script.onload = script.onreadystatechange = function () { 137 | if (!loaded && 138 | (!script.readyState || 139 | "loaded" === script.readyState || 140 | "complete" === script.readyState)) { 141 | 142 | loaded = true; 143 | setTimeout(function () { 144 | cb(false); 145 | }, 0); 146 | } 147 | }; 148 | script.src = url; 149 | head.appendChild(script); 150 | }; 151 | 152 | var normalizeDomain = function (domain) { 153 | // special domain: uems.sysu.edu.cn/jwxt/geetest/ 154 | // return domain.replace(/^https?:\/\/|\/.*$/g, ''); uems.sysu.edu.cn 155 | return domain.replace(/^https?:\/\/|\/$/g, ''); // uems.sysu.edu.cn/jwxt/geetest 156 | }; 157 | var normalizePath = function (path) { 158 | path = path.replace(/\/+/g, '/'); 159 | if (path.indexOf('/') !== 0) { 160 | path = '/' + path; 161 | } 162 | return path; 163 | }; 164 | var normalizeQuery = function (query) { 165 | if (!query) { 166 | return ''; 167 | } 168 | var q = '?'; 169 | new _Object(query)._each(function (key, value) { 170 | if (isString(value) || isNumber(value) || isBoolean(value)) { 171 | q = q + encodeURIComponent(key) + '=' + encodeURIComponent(value) + '&'; 172 | } 173 | }); 174 | if (q === '?') { 175 | q = ''; 176 | } 177 | return q.replace(/&$/, ''); 178 | }; 179 | var makeURL = function (protocol, domain, path, query) { 180 | domain = normalizeDomain(domain); 181 | 182 | var url = normalizePath(path) + normalizeQuery(query); 183 | if (domain) { 184 | url = protocol + domain + url; 185 | } 186 | 187 | return url; 188 | }; 189 | 190 | var load = function (config, send, protocol, domains, path, query, cb) { 191 | var tryRequest = function (at) { 192 | 193 | var url = makeURL(protocol, domains[at], path, query); 194 | loadScript(url, function (err) { 195 | if (err) { 196 | if (at >= domains.length - 1) { 197 | cb(true); 198 | // report gettype error 199 | if (send) { 200 | config.error_code = 508; 201 | var url = protocol + domains[at] + path; 202 | reportError(config, url); 203 | } 204 | } else { 205 | tryRequest(at + 1); 206 | } 207 | } else { 208 | cb(false); 209 | } 210 | }); 211 | }; 212 | tryRequest(0); 213 | }; 214 | 215 | 216 | var jsonp = function (domains, path, config, callback) { 217 | if (isObject(config.getLib)) { 218 | config._extend(config.getLib); 219 | callback(config); 220 | return; 221 | } 222 | if (config.offline) { 223 | callback(config._get_fallback_config()); 224 | return; 225 | } 226 | 227 | var cb = "geetest_" + random(); 228 | window[cb] = function (data) { 229 | if (data.status == 'success') { 230 | callback(data.data); 231 | } else if (!data.status) { 232 | callback(data); 233 | } else { 234 | callback(config._get_fallback_config()); 235 | } 236 | window[cb] = undefined; 237 | try { 238 | delete window[cb]; 239 | } catch (e) { 240 | } 241 | }; 242 | load(config, true, config.protocol, domains, path, { 243 | gt: config.gt, 244 | callback: cb 245 | }, function (err) { 246 | if (err) { 247 | callback(config._get_fallback_config()); 248 | } 249 | }); 250 | }; 251 | 252 | var reportError = function (config, url) { 253 | load(config, false, config.protocol, ['monitor.geetest.com'], '/monitor/send', { 254 | time: nowDate(), 255 | captcha_id: config.gt, 256 | challenge: config.challenge, 257 | pt: pt, 258 | exception_url: url, 259 | error_code: config.error_code 260 | }, function (err) {}) 261 | } 262 | 263 | var throwError = function (errorType, config) { 264 | var errors = { 265 | networkError: '网络错误', 266 | gtTypeError: 'gt字段不是字符串类型' 267 | }; 268 | if (typeof config.onError === 'function') { 269 | config.onError(errors[errorType]); 270 | } else { 271 | throw new Error(errors[errorType]); 272 | } 273 | }; 274 | 275 | var detect = function () { 276 | return window.Geetest || document.getElementById("gt_lib"); 277 | }; 278 | 279 | if (detect()) { 280 | status.slide = "loaded"; 281 | } 282 | 283 | window.initGeetest = function (userConfig, callback) { 284 | 285 | var config = new Config(userConfig); 286 | 287 | if (userConfig.https) { 288 | config.protocol = 'https://'; 289 | } else if (!userConfig.protocol) { 290 | config.protocol = window.location.protocol + '//'; 291 | } 292 | 293 | // for KFC 294 | if (userConfig.gt === '050cffef4ae57b5d5e529fea9540b0d1' || 295 | userConfig.gt === '3bd38408ae4af923ed36e13819b14d42') { 296 | config.apiserver = 'yumchina.geetest.com/'; // for old js 297 | config.api_server = 'yumchina.geetest.com'; 298 | } 299 | 300 | if(userConfig.gt){ 301 | window.GeeGT = userConfig.gt 302 | } 303 | 304 | if(userConfig.challenge){ 305 | window.GeeChallenge = userConfig.challenge 306 | } 307 | 308 | if (isObject(userConfig.getType)) { 309 | config._extend(userConfig.getType); 310 | } 311 | jsonp([config.api_server || config.apiserver], config.typePath, config, function (newConfig) { 312 | var type = newConfig.type; 313 | var init = function () { 314 | config._extend(newConfig); 315 | callback(new window.Geetest(config)); 316 | }; 317 | 318 | callbacks[type] = callbacks[type] || []; 319 | var s = status[type] || 'init'; 320 | if (s === 'init') { 321 | status[type] = 'loading'; 322 | 323 | callbacks[type].push(init); 324 | 325 | load(config, true, config.protocol, newConfig.static_servers || newConfig.domains, newConfig[type] || newConfig.path, null, function (err) { 326 | if (err) { 327 | status[type] = 'fail'; 328 | throwError('networkError', config); 329 | } else { 330 | status[type] = 'loaded'; 331 | var cbs = callbacks[type]; 332 | for (var i = 0, len = cbs.length; i < len; i = i + 1) { 333 | var cb = cbs[i]; 334 | if (isFunction(cb)) { 335 | cb(); 336 | } 337 | } 338 | callbacks[type] = []; 339 | } 340 | }); 341 | } else if (s === "loaded") { 342 | init(); 343 | } else if (s === "fail") { 344 | throwError('networkError', config); 345 | } else if (s === "loading") { 346 | callbacks[type].push(init); 347 | } 348 | }); 349 | 350 | }; 351 | 352 | 353 | })(window); 354 | 355 | -------------------------------------------------------------------------------- /demo/flask_demo/templates/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | gt-python-flask-demo 7 | 65 | 66 | 67 |

极验验证SDKDemo

68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 |

78 | 98 | 99 | 136 |

137 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /demo/tornado_demo/geetest/__init__.py: -------------------------------------------------------------------------------- 1 | from .geetest import GeetestLib, VERSION -------------------------------------------------------------------------------- /demo/tornado_demo/geetest/geetest.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import random 3 | import json 4 | import requests 5 | import time 6 | from hashlib import md5 7 | 8 | if sys.version_info >= (3,): 9 | xrange = range 10 | 11 | VERSION = "3.0.0" 12 | 13 | 14 | class GeetestLib(object): 15 | FN_CHALLENGE = "geetest_challenge" 16 | FN_VALIDATE = "geetest_validate" 17 | FN_SECCODE = "geetest_seccode" 18 | 19 | GT_STATUS_SESSION_KEY = "gt_server_status" 20 | 21 | API_URL = "http://api.geetest.com" 22 | REGISTER_HANDLER = "/register.php" 23 | VALIDATE_HANDLER = "/validate.php" 24 | JSON_FORMAT = False 25 | 26 | def __init__(self, captcha_id, private_key): 27 | self.private_key = private_key 28 | self.captcha_id = captcha_id 29 | self.sdk_version = VERSION 30 | self._response_str = "" 31 | 32 | def pre_process(self, user_id=None, new_captcha=1, JSON_FORMAT=1, client_type="web", ip_address=""): 33 | status, challenge = self._register(user_id, new_captcha, JSON_FORMAT, client_type, ip_address) 34 | self._response_str = self._make_response_format(status, challenge, new_captcha) 35 | return status 36 | 37 | def _register(self, user_id=None, new_captcha=1, JSON_FORMAT=1, client_type="web", ip_address=""): 38 | pri_responce = self._register_challenge(user_id, new_captcha, JSON_FORMAT, client_type, ip_address) 39 | if pri_responce: 40 | if JSON_FORMAT == 1: 41 | response_dic = json.loads(pri_responce) 42 | challenge = response_dic["challenge"] 43 | else: 44 | challenge = pri_responce 45 | else: 46 | challenge = " " 47 | if len(challenge) == 32: 48 | challenge = self._md5_encode("".join([challenge, self.private_key])) 49 | return 1, challenge 50 | else: 51 | return 0, self._make_fail_challenge() 52 | 53 | def get_response_str(self): 54 | return self._response_str 55 | 56 | def _make_fail_challenge(self): 57 | rnd1 = random.randint(0, 99) 58 | rnd2 = random.randint(0, 99) 59 | md5_str1 = self._md5_encode(str(rnd1)) 60 | md5_str2 = self._md5_encode(str(rnd2)) 61 | challenge = md5_str1 + md5_str2[0:2] 62 | return challenge 63 | 64 | def _make_response_format(self, success=1, challenge=None, new_captcha=1): 65 | if not challenge: 66 | challenge = self._make_fail_challenge() 67 | if new_captcha: 68 | string_format = json.dumps( 69 | {'success': success, 'gt': self.captcha_id, 'challenge': challenge, "new_captcha": True}) 70 | else: 71 | string_format = json.dumps( 72 | {'success': success, 'gt': self.captcha_id, 'challenge': challenge, "new_captcha": False}) 73 | return string_format 74 | 75 | def _register_challenge(self, user_id=None, new_captcha=1, JSON_FORMAT=1, client_type="web", ip_address=""): 76 | if user_id: 77 | 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( 78 | api_url=self.API_URL, handler=self.REGISTER_HANDLER, captcha_ID=self.captcha_id, user_id=user_id, 79 | new_captcha=new_captcha, JSON_FORMAT=JSON_FORMAT, client_type=client_type, ip_address=ip_address) 80 | else: 81 | register_url = "{api_url}{handler}?gt={captcha_ID}&json_format={JSON_FORMAT}&client_type={client_type}&ip_address={ip_address}".format( 82 | api_url=self.API_URL, handler=self.REGISTER_HANDLER, captcha_ID=self.captcha_id, 83 | new_captcha=new_captcha, JSON_FORMAT=JSON_FORMAT, client_type=client_type, ip_address=ip_address) 84 | try: 85 | response = requests.get(register_url, timeout=2) 86 | if response.status_code == requests.codes.ok: 87 | res_string = response.text 88 | else: 89 | res_string = "" 90 | except: 91 | res_string = "" 92 | return res_string 93 | 94 | def success_validate(self, challenge, validate, seccode, user_id=None, gt=None, data='', userinfo='', 95 | JSON_FORMAT=1): 96 | """ 97 | 正常模式的二次验证方式.向geetest server 请求验证结果. 98 | """ 99 | if not self._check_para(challenge, validate, seccode): 100 | return 0 101 | if not self._check_result(challenge, validate): 102 | return 0 103 | validate_url = "{api_url}{handler}".format( 104 | api_url=self.API_URL, handler=self.VALIDATE_HANDLER) 105 | query = { 106 | "seccode": seccode, 107 | "sdk": ''.join(["python_", self.sdk_version]), 108 | "user_id": user_id, 109 | "data": data, 110 | "timestamp": time.time(), 111 | "challenge": challenge, 112 | "userinfo": userinfo, 113 | "captchaid": gt, 114 | "json_format": JSON_FORMAT 115 | } 116 | backinfo = self._post_values(validate_url, query) 117 | if JSON_FORMAT == 1: 118 | backinfo = json.loads(backinfo) 119 | backinfo = backinfo["seccode"] 120 | if backinfo == self._md5_encode(seccode): 121 | return 1 122 | else: 123 | return 0 124 | 125 | def _post_values(self, apiserver, data): 126 | response = requests.post(apiserver, data) 127 | return response.text 128 | 129 | def _check_result(self, origin, validate): 130 | encodeStr = self._md5_encode(self.private_key + "geetest" + origin) 131 | if validate == encodeStr: 132 | return True 133 | else: 134 | return False 135 | 136 | def failback_validate(self, challenge, validate, seccode): 137 | """ 138 | failback模式的二次验证方式.在本地对轨迹进行简单的判断返回验证结果. 139 | """ 140 | if not self._check_para(challenge, validate, seccode): 141 | return 0 142 | validate_result = self._failback_check_result( 143 | challenge, validate, ) 144 | return validate_result 145 | 146 | def _failback_check_result(self, challenge, validate): 147 | encodeStr = self._md5_encode(challenge) 148 | if validate == encodeStr: 149 | return True 150 | else: 151 | return False 152 | 153 | def _check_para(self, challenge, validate, seccode): 154 | return (bool(challenge.strip()) and bool(validate.strip()) and bool(seccode.strip())) 155 | 156 | def _md5_encode(self, values): 157 | if type(values) == str: 158 | values = values.encode() 159 | m = md5(values) 160 | return m.hexdigest() 161 | -------------------------------------------------------------------------------- /demo/tornado_demo/requirements.txt: -------------------------------------------------------------------------------- 1 | torndsession 2 | requests 3 | -------------------------------------------------------------------------------- /demo/tornado_demo/start.py: -------------------------------------------------------------------------------- 1 | import json 2 | import tornado.gen 3 | import tornado.ioloop 4 | import tornado.web 5 | from torndsession.session import SessionManager 6 | from torndsession.sessionhandler import SessionBaseHandler 7 | 8 | from geetest import GeetestLib 9 | 10 | #请在官网申请ID使用,示例ID不可使用 11 | pc_geetest_id = "48a6ebac4ebc6642d68c217fca33eb4d" 12 | pc_geetest_key = "4f1c085290bec5afdc54df73535fc361" 13 | 14 | product = "embed" 15 | 16 | 17 | class MainHandler(tornado.web.RequestHandler): 18 | def get(self): 19 | self.render("static/login.html",) 20 | 21 | class JsHandler(tornado.web.RequestHandler): 22 | def get(self): 23 | self.render("static/gt.js",) 24 | 25 | 26 | class PcGetCaptchaHandler(SessionBaseHandler): 27 | def get(self): 28 | user_id = 'test' 29 | gt = GeetestLib(pc_geetest_id, pc_geetest_key) 30 | status = gt.pre_process(user_id,JSON_FORMAT=0,ip_address="127.0.0.1") 31 | if not status: 32 | status=2 33 | self.session[gt.GT_STATUS_SESSION_KEY] = status 34 | self.session["user_id"] = user_id 35 | response_str = gt.get_response_str() 36 | self.write(response_str) 37 | 38 | 39 | class PcValidateHandler(SessionBaseHandler): 40 | def post(self): 41 | gt = GeetestLib(pc_geetest_id, pc_geetest_key) 42 | challenge = self.get_argument(gt.FN_CHALLENGE, "") 43 | validate = self.get_argument(gt.FN_VALIDATE, "") 44 | seccode = self.get_argument(gt.FN_SECCODE, "") 45 | status = self.session[gt.GT_STATUS_SESSION_KEY] 46 | user_id = self.session["user_id"] 47 | if status==1: 48 | result = gt.success_validate(challenge, validate, seccode, user_id,JSON_FORMAT=0) 49 | else: 50 | result = gt.failback_validate(challenge, validate, seccode) 51 | self.session["user_id"] = user_id 52 | result = "

登录成功

" if result else "

登录失败

" 53 | self.write(result) 54 | 55 | if __name__ == "__main__": 56 | app = tornado.web.Application([ 57 | (r"/", MainHandler), 58 | (r"/static/gt.js",JsHandler), 59 | (r"/pc-geetest/register", PcGetCaptchaHandler), 60 | (r"/pc-geetest/validate", PcValidateHandler), 61 | ], debug=True) 62 | 63 | app.listen(8088) 64 | tornado.ioloop.IOLoop.instance().start() 65 | -------------------------------------------------------------------------------- /demo/tornado_demo/static/gt.js: -------------------------------------------------------------------------------- 1 | "v0.4.8 Geetest Inc."; 2 | 3 | (function (window) { 4 | "use strict"; 5 | if (typeof window === 'undefined') { 6 | throw new Error('Geetest requires browser environment'); 7 | } 8 | 9 | var document = window.document; 10 | var Math = window.Math; 11 | var head = document.getElementsByTagName("head")[0]; 12 | 13 | function _Object(obj) { 14 | this._obj = obj; 15 | } 16 | 17 | _Object.prototype = { 18 | _each: function (process) { 19 | var _obj = this._obj; 20 | for (var k in _obj) { 21 | if (_obj.hasOwnProperty(k)) { 22 | process(k, _obj[k]); 23 | } 24 | } 25 | return this; 26 | } 27 | }; 28 | 29 | function Config(config) { 30 | var self = this; 31 | new _Object(config)._each(function (key, value) { 32 | self[key] = value; 33 | }); 34 | } 35 | 36 | Config.prototype = { 37 | api_server: 'api.geetest.com', 38 | protocol: 'http://', 39 | typePath: '/gettype.php', 40 | fallback_config: { 41 | slide: { 42 | static_servers: ["static.geetest.com", "dn-staticdown.qbox.me"], 43 | type: 'slide', 44 | slide: '/static/js/geetest.0.0.0.js' 45 | }, 46 | fullpage: { 47 | static_servers: ["static.geetest.com", "dn-staticdown.qbox.me"], 48 | type: 'fullpage', 49 | fullpage: '/static/js/fullpage.0.0.0.js' 50 | } 51 | }, 52 | _get_fallback_config: function () { 53 | var self = this; 54 | if (isString(self.type)) { 55 | return self.fallback_config[self.type]; 56 | } else if (self.new_captcha) { 57 | return self.fallback_config.fullpage; 58 | } else { 59 | return self.fallback_config.slide; 60 | } 61 | }, 62 | _extend: function (obj) { 63 | var self = this; 64 | new _Object(obj)._each(function (key, value) { 65 | self[key] = value; 66 | }) 67 | } 68 | }; 69 | var isNumber = function (value) { 70 | return (typeof value === 'number'); 71 | }; 72 | var isString = function (value) { 73 | return (typeof value === 'string'); 74 | }; 75 | var isBoolean = function (value) { 76 | return (typeof value === 'boolean'); 77 | }; 78 | var isObject = function (value) { 79 | return (typeof value === 'object' && value !== null); 80 | }; 81 | var isFunction = function (value) { 82 | return (typeof value === 'function'); 83 | }; 84 | var MOBILE = /Mobi/i.test(navigator.userAgent); 85 | var pt = MOBILE ? 3 : 0; 86 | 87 | var callbacks = {}; 88 | var status = {}; 89 | 90 | var nowDate = function () { 91 | var date = new Date(); 92 | var year = date.getFullYear(); 93 | var month = date.getMonth() + 1; 94 | var day = date.getDate(); 95 | var hours = date.getHours(); 96 | var minutes = date.getMinutes(); 97 | var seconds = date.getSeconds(); 98 | 99 | if (month >= 1 && month <= 9) { 100 | month = '0' + month; 101 | } 102 | if (day >= 0 && day <= 9) { 103 | day = '0' + day; 104 | } 105 | if (hours >= 0 && hours <= 9) { 106 | hours = '0' + hours; 107 | } 108 | if (minutes >= 0 && minutes <= 9) { 109 | minutes = '0' + minutes; 110 | } 111 | if (seconds >= 0 && seconds <= 9) { 112 | seconds = '0' + seconds; 113 | } 114 | var currentdate = year + '-' + month + '-' + day + " " + hours + ":" + minutes + ":" + seconds; 115 | return currentdate; 116 | } 117 | 118 | var random = function () { 119 | return parseInt(Math.random() * 10000) + (new Date()).valueOf(); 120 | }; 121 | 122 | var loadScript = function (url, cb) { 123 | var script = document.createElement("script"); 124 | script.charset = "UTF-8"; 125 | script.async = true; 126 | 127 | // 对geetest的静态资源添加 crossOrigin 128 | if ( /static\.geetest\.com/g.test(url)) { 129 | script.crossOrigin = "anonymous"; 130 | } 131 | 132 | script.onerror = function () { 133 | cb(true); 134 | }; 135 | var loaded = false; 136 | script.onload = script.onreadystatechange = function () { 137 | if (!loaded && 138 | (!script.readyState || 139 | "loaded" === script.readyState || 140 | "complete" === script.readyState)) { 141 | 142 | loaded = true; 143 | setTimeout(function () { 144 | cb(false); 145 | }, 0); 146 | } 147 | }; 148 | script.src = url; 149 | head.appendChild(script); 150 | }; 151 | 152 | var normalizeDomain = function (domain) { 153 | // special domain: uems.sysu.edu.cn/jwxt/geetest/ 154 | // return domain.replace(/^https?:\/\/|\/.*$/g, ''); uems.sysu.edu.cn 155 | return domain.replace(/^https?:\/\/|\/$/g, ''); // uems.sysu.edu.cn/jwxt/geetest 156 | }; 157 | var normalizePath = function (path) { 158 | path = path.replace(/\/+/g, '/'); 159 | if (path.indexOf('/') !== 0) { 160 | path = '/' + path; 161 | } 162 | return path; 163 | }; 164 | var normalizeQuery = function (query) { 165 | if (!query) { 166 | return ''; 167 | } 168 | var q = '?'; 169 | new _Object(query)._each(function (key, value) { 170 | if (isString(value) || isNumber(value) || isBoolean(value)) { 171 | q = q + encodeURIComponent(key) + '=' + encodeURIComponent(value) + '&'; 172 | } 173 | }); 174 | if (q === '?') { 175 | q = ''; 176 | } 177 | return q.replace(/&$/, ''); 178 | }; 179 | var makeURL = function (protocol, domain, path, query) { 180 | domain = normalizeDomain(domain); 181 | 182 | var url = normalizePath(path) + normalizeQuery(query); 183 | if (domain) { 184 | url = protocol + domain + url; 185 | } 186 | 187 | return url; 188 | }; 189 | 190 | var load = function (config, send, protocol, domains, path, query, cb) { 191 | var tryRequest = function (at) { 192 | 193 | var url = makeURL(protocol, domains[at], path, query); 194 | loadScript(url, function (err) { 195 | if (err) { 196 | if (at >= domains.length - 1) { 197 | cb(true); 198 | // report gettype error 199 | if (send) { 200 | config.error_code = 508; 201 | var url = protocol + domains[at] + path; 202 | reportError(config, url); 203 | } 204 | } else { 205 | tryRequest(at + 1); 206 | } 207 | } else { 208 | cb(false); 209 | } 210 | }); 211 | }; 212 | tryRequest(0); 213 | }; 214 | 215 | 216 | var jsonp = function (domains, path, config, callback) { 217 | if (isObject(config.getLib)) { 218 | config._extend(config.getLib); 219 | callback(config); 220 | return; 221 | } 222 | if (config.offline) { 223 | callback(config._get_fallback_config()); 224 | return; 225 | } 226 | 227 | var cb = "geetest_" + random(); 228 | window[cb] = function (data) { 229 | if (data.status == 'success') { 230 | callback(data.data); 231 | } else if (!data.status) { 232 | callback(data); 233 | } else { 234 | callback(config._get_fallback_config()); 235 | } 236 | window[cb] = undefined; 237 | try { 238 | delete window[cb]; 239 | } catch (e) { 240 | } 241 | }; 242 | load(config, true, config.protocol, domains, path, { 243 | gt: config.gt, 244 | callback: cb 245 | }, function (err) { 246 | if (err) { 247 | callback(config._get_fallback_config()); 248 | } 249 | }); 250 | }; 251 | 252 | var reportError = function (config, url) { 253 | load(config, false, config.protocol, ['monitor.geetest.com'], '/monitor/send', { 254 | time: nowDate(), 255 | captcha_id: config.gt, 256 | challenge: config.challenge, 257 | pt: pt, 258 | exception_url: url, 259 | error_code: config.error_code 260 | }, function (err) {}) 261 | } 262 | 263 | var throwError = function (errorType, config) { 264 | var errors = { 265 | networkError: '网络错误', 266 | gtTypeError: 'gt字段不是字符串类型' 267 | }; 268 | if (typeof config.onError === 'function') { 269 | config.onError(errors[errorType]); 270 | } else { 271 | throw new Error(errors[errorType]); 272 | } 273 | }; 274 | 275 | var detect = function () { 276 | return window.Geetest || document.getElementById("gt_lib"); 277 | }; 278 | 279 | if (detect()) { 280 | status.slide = "loaded"; 281 | } 282 | 283 | window.initGeetest = function (userConfig, callback) { 284 | 285 | var config = new Config(userConfig); 286 | 287 | if (userConfig.https) { 288 | config.protocol = 'https://'; 289 | } else if (!userConfig.protocol) { 290 | config.protocol = window.location.protocol + '//'; 291 | } 292 | 293 | // for KFC 294 | if (userConfig.gt === '050cffef4ae57b5d5e529fea9540b0d1' || 295 | userConfig.gt === '3bd38408ae4af923ed36e13819b14d42') { 296 | config.apiserver = 'yumchina.geetest.com/'; // for old js 297 | config.api_server = 'yumchina.geetest.com'; 298 | } 299 | 300 | if(userConfig.gt){ 301 | window.GeeGT = userConfig.gt 302 | } 303 | 304 | if(userConfig.challenge){ 305 | window.GeeChallenge = userConfig.challenge 306 | } 307 | 308 | if (isObject(userConfig.getType)) { 309 | config._extend(userConfig.getType); 310 | } 311 | jsonp([config.api_server || config.apiserver], config.typePath, config, function (newConfig) { 312 | var type = newConfig.type; 313 | var init = function () { 314 | config._extend(newConfig); 315 | callback(new window.Geetest(config)); 316 | }; 317 | 318 | callbacks[type] = callbacks[type] || []; 319 | var s = status[type] || 'init'; 320 | if (s === 'init') { 321 | status[type] = 'loading'; 322 | 323 | callbacks[type].push(init); 324 | 325 | load(config, true, config.protocol, newConfig.static_servers || newConfig.domains, newConfig[type] || newConfig.path, null, function (err) { 326 | if (err) { 327 | status[type] = 'fail'; 328 | throwError('networkError', config); 329 | } else { 330 | status[type] = 'loaded'; 331 | var cbs = callbacks[type]; 332 | for (var i = 0, len = cbs.length; i < len; i = i + 1) { 333 | var cb = cbs[i]; 334 | if (isFunction(cb)) { 335 | cb(); 336 | } 337 | } 338 | callbacks[type] = []; 339 | } 340 | }); 341 | } else if (s === "loaded") { 342 | init(); 343 | } else if (s === "fail") { 344 | throwError('networkError', config); 345 | } else if (s === "loading") { 346 | callbacks[type].push(init); 347 | } 348 | }); 349 | 350 | }; 351 | 352 | 353 | })(window); 354 | 355 | -------------------------------------------------------------------------------- /demo/tornado_demo/static/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | gt-python-tornado-demo 7 | 65 | 66 | 67 |

极验验证SDKDemo

68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 |

79 | 99 | 100 | 137 |

138 | 139 | 140 | 141 | --------------------------------------------------------------------------------