[reCAPTCHA]typecho添加reCAPTCHA验证码

Head Pic: 【女の子】"miku 环绕声" / Illustration by "千夜QYS3" [pixiv]

发现typecho的这类插件很少,而且很难用,所以干脆现学现卖自己整个。

具体效果看本站的登陆界面就行了,handsome快捷登陆在右上角,typecho登陆则在https://4o5.xyz/admin/login.php

概述

虽然typecho的这方面插件少,但是其本身的设计模式确实非常ok的:

admin/login.php用来前端登陆,var/Widget/Login.php则处理登陆逻辑。

所以我们改动也就只需改这里就行啦,记得做好备份。

reCaptcha申请

前往https://www.google.com/recaptcha/admin 申请一个key,只有这一步需要访问google.com,其余不再需要。代码已经使用recaptcha的google官方反向代理,国内正常使用。

申请的时候记得选择reCAPTCHA v2版本,v3我没试过不保证成功。

登陆界面集成

admin/login.php中(这里是相对于typecho的安装位置)

引入js:<script src="https://www.recaptcha.net/recaptcha/api.js"></script>(不会的话就随便放在一个<div>标签的前面)

然后大概在第26行,就是<input type="password"......><p></p>标签后面一行加入。

<p>
    <div class="g-recaptcha" data-sitekey="your-site-key"></div>
</p>

记得将上面的your-site-key替换成你申请的鸭。

这样前端就有了人机身份验证的checkbox了。

登陆验证集成

var/Widget/Login.php中,这里改动很多直接替换吧(没有后门脚本,仅加入了recaptcha相关逻辑处理代码):

<?php
if (!defined('__TYPECHO_ROOT_DIR__')) exit;
/**
 * 登录动作
 *
 * @category typecho
 * @package Widget
 * @copyright Copyright (c) 2008 Typecho team (http://www.typecho.org)
 * @license GNU General Public License 2.0
 * @version $Id$
 */

/**
 * 登录组件
 *
 * @category typecho
 * @package Widget
 * @copyright Copyright (c) 2008 Typecho team (http://www.typecho.org)
 * @license GNU General Public License 2.0
 */
class Paul_GCaptcha {
    public static $success, $failed;

    // 发送验证信息
    public static function send($post_data) {
        $postdata = http_build_query($post_data);
        $options = array(
            'http' => array(
                'method' => 'POST',
                'header' => 'Content-type:application/x-www-form-urlencoded',
                'content' => $postdata,
                'timeout' => 15 * 60 // 超时时间
            )
        );
        $context = stream_context_create($options);  
        $result = file_get_contents("https://recaptcha.net/recaptcha/api/siteverify", false, $context);
        return $result;
    }

    // 判断验证状况
    public static function check(){
        if($_POST["g-recaptcha-response"]){
            $data = array(
                'secret' => 'your-secret-key',
                'response' => $_POST["g-recaptcha-response"] // 接收用户提交的验证数据
            );

            $result = self::send($data);
            $result = json_decode($result, true);
            $result = $result["success"];

            if($result == true){
                return true; // 验证成功
            }
            else{
                return false; // 验证失败
            }
        }
        else{
            return false; // 用户没有提交到验证信息
        }
    }
}

class Widget_Login extends Widget_Abstract_Users implements Widget_Interface_Do
{
    /**
     * 初始化函数
     *
     * @access public
     * @return void
     */
    public function action()
    {
        // protect
        $this->security->protect();

        /** 如果已经登录 */
        if ($this->user->hasLogin()) {
            /** 直接返回 */
            $this->response->redirect($this->options->index);
        }

        /** 初始化验证类 */
        $validator = new Typecho_Validate();
        $validator->addRule('name', 'required', _t('请输入用户名'));
        $validator->addRule('password', 'required', _t('请输入密码'));

        /** 截获验证异常 */
        if ($error = $validator->run($this->request->from('name', 'password'))) {
            Typecho_Cookie::set('__typecho_remember_name', $this->request->name);

            /** 设置提示信息 */
            $this->widget('Widget_Notice')->set($error);
            $this->response->goBack();
        }

        if(Paul_GCaptcha::check() == true){
            /** 开始验证用户 **/
            $valid = $this->user->login($this->request->name, $this->request->password,
            false, 1 == $this->request->remember ? $this->options->time + $this->options->timezone + 30*24*3600 : 0);

            /** 比对密码 */
            if (!$valid) {
                /** 防止穷举,休眠3秒 */
                sleep(3);

                $this->pluginHandle()->loginFail($this->user, $this->request->name,
                $this->request->password, 1 == $this->request->remember);

                Typecho_Cookie::set('__typecho_remember_name', $this->request->name);
                $this->widget('Widget_Notice')->set(_t('用户名或密码无效'), 'error');
                $this->response->goBack('?referer=' . urlencode($this->request->referer));
            }
            $this->pluginHandle()->loginSucceed($this->user, $this->request->name,
            $this->request->password, 1 == $this->request->remember);

            /** 跳转验证后地址 */
            if (NULL != $this->request->referer) {
                $this->response->redirect($this->request->referer);
            } else if (!$this->user->pass('contributor', true)) {
                /** 不允许普通用户直接跳转后台 */
                $this->response->redirect($this->options->profileUrl);
            } else {
                $this->response->redirect($this->options->adminUrl);
            }
        }else{
            $this->widget('Widget_Notice')->set(_t('验证失败'),'error');
            $this->response->goBack('?referer=' . urlencode($this->request->referer));
        }
    }
}

记得将里面的yout-secret-key换成你自己的鸭。

然后就成功了。

(这里的验证代码来自https://paugram.com/coding/add-recaptcha.html,原谅我的懒惰)

handsome快捷登陆集成

如果像我一样使用handsome的,上述改动也会让这里无法登陆,所以快捷登陆这里也集成recaptcha吧。

改动不多,这个有版权不适合放出整个文件嘻嘻。

usr/themes/handsome/component/headnav.php

引入js:<script src="https://www.recaptcha.net/recaptcha/api.js"></script>

大概在第236行,也就是有一个<input type="password"......>后面一行,加入下面的代码:

<div class="g-recaptcha" data-sitekey="your-site-key"></div>

同理,记得将上面的your-site-key替换成你申请的鸭。

最后修改:2019 年 08 月 02 日 08 : 25 PM

1 条评论

  1. Cinema

    滴!访客卡!请上车的乘客系好安全带,现在是:Sat Aug 03 2019 09:47:09 GMT+0800 (中國標準時間)

发表评论