Typecho 集成 Geetest 4.0 人机验证教程


4 观看次数
804 字数
0 评论

准备工作

在开始集成之前,请确保您已准备好以下事项:

  • Geetest 账户:注册并登录 Geetest 官方网站
  • Geetest V4 凭证:在 Geetest 后台创建一个新的 V4 验证,并获取其对应的 CAPTCHA_IDCAPTCHA_KEY

集成原理

我们将采用“后端先行”的验证模式,其核心流程如下:

Typecho接入Geetest的工作流程图.png

实施步骤:以登录页面为例

我们将首先以最核心的后台登录页面为例,完整地走通集成流程。

步骤一:修改后端登录逻辑 (var/Widget/Login.php)

这是集成的核心。我们需要让 Typecho 在处理登录时,先去问询 Geetest 服务器。

  1. 打开 var/Widget/Login.php 文件。
  2. Widget_Login 类中,添加两个新的私有方法:_geetestValidate() 用于处理二次验证逻辑,_sendPost() 用于发送 HTTP 请求。

    /**
     * [Geetest] 新增:用于Geetest二次验证的私有方法
     */
    private function _geetestValidate($lot_number, $captcha_output, $pass_token, $gen_time)
    {
        // --- 请在这里填入你的Geetest凭证 ---
        $captcha_id = '你的_CAPTCHA_ID';
        $captcha_key = '你的_CAPTCHA_KEY';
        // ------------------------------------
    
        $api_server = 'http://gcaptcha4.geetest.com';
        $sign_token = hash_hmac('sha256', $lot_number, $captcha_key);
        $post_data = [
            'lot_number'     => $lot_number,
            'captcha_output' => $captcha_output,
            'pass_token'     => $pass_token,
            'gen_time'       => $gen_time,
            'sign_token'     => $sign_token,
        ];
    
        $url = $api_server . '/validate?captcha_id=' . $captcha_id;
        $response_json = $this->_sendPost($url, $post_data);
        
        return json_decode($response_json, true);
    }
    
    /** 
     * [Geetest] 新增:用于发送POST请求的私有方法
     */
    private function _sendPost($url, $post_data)
    {
        $postdata = http_build_query($post_data);
        $options = [
            'http' => [
                'method'  => 'POST',
                'header'  => 'Content-type:application/x-www-form-urlencoded',
                'content' => $postdata,
                'timeout' => 20,
            ],
        ];
        $context = stream_context_create($options);
        $result = file_get_contents($url, false, $context);
        return $result;
    }
  3. 找到 action() 方法,并对其进行修改:

    public function action()
    {
        // ... (前面的代码保持不变)
    
        /** 初始化验证类 */
        $validator = new Typecho_Validate(); // 或 new Validate(),取决于你的Typecho版本
        $validator->addRule('name', 'required', _t('请输入用户名'));
        $validator->addRule('password', 'required', _t('请输入密码'));
        // [Geetest] 添加新的验证规则,检查核心参数是否存在
        $validator->addRule('lot_number', 'required', _t('请完成人机验证'));
    
        /** 截获验证异常 */
        // [Geetest] 将 lot_number 加入验证列表
        if ($error = $validator->run($this->request->from('name', 'password', 'lot_number'))) {
            // ... (这里的代码保持不变)
        }
    
        /** [Geetest] 在验证用户名密码前,执行二次验证 */
        $geetest_result = $this->_geetestValidate(
            $this->request->get('lot_number'),
            $this->request->get('captcha_output'),
            $this->request->get('pass_token'),
            $this->request->get('gen_time')
        );
    
        if (!$geetest_result || $geetest_result['result'] !== 'success') {
            /** 设置提示信息 */
            $reason = isset($geetest_result['reason']) ? $geetest_result['reason'] : 'Unknown Error';
            $this->widget('Widget_Notice')->set(_t('人机验证失败: ') . $reason); // 或 Notice::alloc()->set()
            $this->response->goBack();
        }
    
        /** 开始验证用户 (原有的登录逻辑) **/
        // ... (后续的 $this->user->login() 等代码保持不变)
    }

步骤二:修改前台登录模板 (admin/login.php)

现在我们需要在前端页面上显示验证码并配合后端的逻辑。

  1. 打开 admin/login.php 文件。
  2. 在表单中,于“密码”输入框和“登录”按钮之间,添加一个用于承载验证码的容器。

    <!-- ... 密码输入框 ... -->
    <p>
    <label for="password" class="sr-only"><?php _e('密码'); ?></label>
    <input type="password" id="password" name="password" ... />
    </p>
    
    <!-- [Geetest] 验证码容器 -->
    <div id="captcha-container" style="margin-bottom: 1.2rem;"></div>
    
    <!-- [优化] Banner 提示将会被动态插入到这里 -->
    
    <p class="submit">
    <button type="submit" ...><?php _e('登录'); ?></button>
    ...
    </p>
    <!-- ... -->
  3. 在文件底部 <?php include 'footer.php'; ?> 之前,添加 Geetest 的 JS 库引用和初始化脚本。

    > **最佳实践**:为了提供更好的用户体验,我们使用内联的 Banner 提示代替 `alert()` 弹窗。
    
    首先,在 `admin/login.php` 文件顶部添加 Banner 的 CSS 样式。
    <style>
    .geetest-banner {
    background-color: #f8d7da; color: #721c24; padding: 10px 15px;
    margin-bottom: 1.2rem; border-radius: .25rem; text-align: center;
    }
    </style>
    然后,添加以下 JavaScript 代码。
    <!-- [Geetest] 引入 Geetest JS 并添加初始化脚本 -->
    <script src="https://static.geetest.com/v4/gt4.js"></script>
    <script>
    document.addEventListener('DOMContentLoaded', function () {
    // --- 请在这里填入你的 Geetest CAPTCHA_ID ---
    var geetestCaptchaId = '你的_CAPTCHA_ID';
    // ------------------------------------
    
    var form = document.querySelector('form[name="login"]');
    var captchaInstance = null;
    
    // Banner 提示函数
    function showBannerMessage(message) {
    removeBannerMessage();
    var banner = document.createElement('div');
    banner.id = 'geetest-banner';
    banner.className = 'geetest-banner';
    banner.textContent = message;
    form.insertBefore(banner, form.querySelector('.submit'));
    }
    function removeBannerMessage() {
    var banner = document.getElementById('geetest-banner');
    if (banner) banner.remove();
    }
    
    initGeetest4({ captchaId: geetestCaptchaId }, function (captcha) {
    captchaInstance = captcha;
    captcha.appendTo('#captcha-container');
    });
    
    form.addEventListener('submit', function (e) {
    removeBannerMessage();
    if (!captchaInstance) {
        showBannerMessage('验证码加载中,请稍候。');
        e.preventDefault(); return;
    }
    var result = captchaInstance.getValidate();
    if (!result) {
        showBannerMessage('请先完成人机验证!');
        e.preventDefault();
    } else {
        Object.keys(result).forEach(function(key) {
            if (!form.querySelector('input[name="' + key + '"]')) {
                var input = document.createElement('input');
                input.type = 'hidden';
                input.name = key;
                input.value = result[key];
                form.appendChild(input);
            }
        });
    }
    });
    });
    </script>

扩展至注册页面

将 Geetest 应用于注册页面的方法与登录页完全相同,只需重复以上步骤,但操作于对应的注册文件。

  • 后端文件var/Widget/Register.php
  • 前台文件admin/register.php

操作要点

  1. Widget_Register.php 中,同样添加 _geetestValidate()_sendPost() 方法。
  2. Widget_Register::action() 方法中,参照 Widget_Login::action() 的修改方式,在执行用户数据插入数据库之前,加入 Geetest 的二次验证逻辑。
  3. admin/register.php 中,同样添加验证码容器 <div> 和底部的 JavaScript 初始化脚本。

总结

通过遵循本教程,将 Geetest 4.0 以一种安全、稳定且符合 Typecho 框架设计的方式集成到了您的网站中。这种深度集成的方法不仅提升了安全性,还保证了代码的可维护性。当 Typecho 版本更新时,只需关注 Widget 和模板文件的相应变化,即可轻松地迁移您的安全防护功能。


评论区

还没有人评论

添加新评论