前言#
私たちの Typecho ブログをより良く保護するために、Typecho の管理画面のログイン / 登録画面に Google の reCAPTCHA 認証サービスを追加することにしました。
教程#
reCAPTCHA を取得する#
ヒント:このステップでは Google アカウントと科学的なインターネット接続が必要です。条件がない場合は、コメント欄でプライベートにコメントして、ブロガーに申請を手伝ってもらってください(ブロガーはコメント欄とコメント時に提供されたメールアドレスを通じて必要な内容を送信します):::
まず、[reCAPTCHA 公式サイト][1] を開きます。
![1][2]
次に、上部の v3 Admin Console をクリックします。
Google アカウントにログインします。
![2][3]
次に、[この][4] リンクを開きます。
![3][5]
ラベルは適当に書いてください(例えば、あるオープンワールドゲームなど)。
reCAPTCHA タイプは reCAPTCHA 第 2 版 を選択 → 「人間かどうかを確認する」チェックボックスを選択します。
下にスクロールして ドメイン を見つけ、あなたのブログのドメインを入力します。必要に応じていくつか追加することもできます。
一番下までスクロールして 送信 をクリックします。
これで SiteKey と Secert Key を取得できます。
![4][6]
この 2 つのキーをメモして保存しておいてください。後で使用します。
reCAPTCHA をインストールする#
管理画面で変更する項目が多いため、初心者のために、以下の内容をそのまま上書きしてください。
ログインページ#
以下の内容を /admin/login.php に上書きします。
<?php
include 'common.php';
if ($user->hasLogin()) {
$response->redirect($options->adminUrl);
}
$rememberName = htmlspecialchars(Typecho_Cookie::get('__typecho_remember_name'));
Typecho_Cookie::delete('__typecho_remember_name');
$bodyClass = 'body-100';
include 'header.php';
?>
<div class="typecho-login-wrap">
<div class="typecho-login">
<h1><a href="http://typecho.org" class="i-logo">Typecho</a></h1>
<form action="<?php $options->loginAction(); ?>" method="post" name="login" role="form">
<p>
<label for="name" class="sr-only"><?php _e('ユーザー名'); ?></label>
<input type="text" id="name" name="name" value="<?php echo $rememberName; ?>" placeholder="<?php _e('ユーザー名'); ?>" class="text-l w-100" autofocus />
</p>
<p>
<label for="password" class="sr-only"><?php _e('パスワード'); ?></label>
<input type="password" id="password" name="password" class="text-l w-100" placeholder="<?php _e('パスワード'); ?>" />
</p>
<p class="submit">
<button type="submit" class="btn btn-l w-100 primary"><?php _e('ログイン'); ?></button>
<input type="hidden" name="referer" value="<?php echo htmlspecialchars($request->get('referer')); ?>" />
</p>
<script src="https://www.recaptcha.net/recaptcha/api.js"></script> <!-- google -->
<p>
<div class="g-recaptcha" data-sitekey="ここにあなたのSITEキーを入力してください"></div><!-- google -->
</p>
<p>
<p>
<label for="remember"><input type="checkbox" name="remember" class="checkbox" value="1" id="remember" /> <?php _e('次回自動ログイン'); ?></label>
</p>
</form>
<p class="more-link">
<a href="<?php $options->siteUrl(); ?>"><?php _e('ホームに戻る'); ?></a>
<?php if($options->allowRegister): ?>
•
<a href="<?php $options->registerUrl(); ?>"><?php _e('ユーザー登録'); ?></a>
<?php endif; ?>
</p>
</div>
</div>
<?php
include 'common-js.php';
?>
<script>
$(document).ready(function () {
$('#name').focus();
});
</script>
<?php
include 'footer.php';
?>
以下の内容を /var/Widget/Login.php に上書きします。
<?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
*/
/**
* reCAPTCHA
*
* By BLxcwg666
* https://blog.xcnya.cn
* [email protected]
*/
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' => 'ここにあなたのSECRETキーを入力してください',
'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()
{
// 保護
$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));
}
}
}
上記のフィールドを自分の SiteKey と Secert Key に置き換えます。
登録ページ#
以下の内容を /admin/register.php に上書きします。
<?php
include 'common.php';
if ($user->hasLogin() || !$options->allowRegister) {
$response->redirect($options->siteUrl);
}
$rememberName = htmlspecialchars(Typecho_Cookie::get('__typecho_remember_name'));
$rememberMail = htmlspecialchars(Typecho_Cookie::get('__typecho_remember_mail'));
Typecho_Cookie::delete('__typecho_remember_name');
Typecho_Cookie::delete('__typecho_remember_mail');
$bodyClass = 'body-100';
include 'header.php';
?>
<div class="typecho-login-wrap">
<div class="typecho-login">
<h1><a href="http://typecho.org" class="i-logo">Typecho</a></h1>
<form action="<?php $options->registerAction(); ?>" method="post" name="register" role="form">
<p>
<label for="name" class="sr-only"><?php _e('ユーザー名'); ?></label>
<input type="text" id="name" name="name" placeholder="<?php _e('ユーザー名'); ?>" value="<?php echo $rememberName; ?>" class="text-l w-100" autofocus />
</p>
<p>
<label for="mail" class="sr-only"><?php _e('Email'); ?></label>
<input type="email" id="mail" name="mail" placeholder="<?php _e('Email'); ?>" value="<?php echo $rememberMail; ?>" class="text-l w-100" />
</p>
<div class="g-recaptcha" data-sitekey="ここにあなたのSITEキーを入力してください"></div>
</p>
<p class="submit">
<button type="submit" class="btn btn-l w-100 primary"><?php _e('登録'); ?></button>
</p>
<script src="https://www.recaptcha.net/recaptcha/api.js"></script>
<p>
</form>
<p class="more-link">
<a href="<?php $options->siteUrl(); ?>"><?php _e('ホームに戻る'); ?></a>
•
<a href="<?php $options->adminUrl('login.php'); ?>"><?php _e('ユーザーログイン'); ?></a>
</p>
</div>
</div>
<?php
include 'common-js.php';
?>
<script>
$(document).ready(function () {
$('#name').focus();
});
</script>
<?php
include 'footer.php';
?>
以下の内容を /var/Widget/Register.php に上書きします。
<?php
if (!defined('__TYPECHO_ROOT_DIR__')) exit;
/**
* 登録コンポーネント
*
* @author qining
* @category typecho
* @package Widget
*/
/**
* reCAPTCHA
*
* By BLxcwg666
* https://blog.xcnya.cn
* [email protected]
*/
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' => 'ここにあなたのSECERTキーを入力してください',
'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_Register extends Widget_Abstract_Users implements Widget_Interface_Do
{
/**
* 初期化関数
*
* @access public
* @return void
*/
public function action()
{
// 保護
$this->security->protect();
/** すでにログインしている場合 */
if ($this->user->hasLogin() || !$this->options->allowRegister) {
/** 直接戻る */
$this->response->redirect($this->options->index);
}
/** 認証クラスを初期化 */
$validator = new Typecho_Validate();
$validator->addRule('name', 'required', _t('ユーザー名を入力してください'));
$validator->addRule('name', 'minLength', _t('ユーザー名は少なくとも2文字以上である必要があります'), 2);
$validator->addRule('name', 'maxLength', _t('ユーザー名は最大32文字までです'), 32);
$validator->addRule('name', 'xssCheck', _t('ユーザー名に特殊文字を使用しないでください'));
$validator->addRule('name', array($this, 'nameExists'), _t('ユーザー名はすでに存在します'));
$validator->addRule('mail', 'required', _t('電子メールアドレスを入力してください'));
$validator->addRule('mail', array($this, 'mailExists'), _t('電子メールアドレスはすでに存在します'));
$validator->addRule('mail', 'email', _t('電子メールの形式が無効です'));
$validator->addRule('mail', 'maxLength', _t('電子メールは最大200文字までです'), 200);
/** リクエストにパスワードが含まれている場合 */
if (array_key_exists('password', $_REQUEST)) {
$validator->addRule('password', 'required', _t('パスワードを入力してください'));
$validator->addRule('password', 'minLength', _t('アカウントの安全のため、少なくとも6文字のパスワードを入力してください'), 6);
$validator->addRule('password', 'maxLength', _t('覚えやすさのため、パスワードの長さは18文字を超えないでください'), 18);
$validator->addRule('confirm', 'confirm', _t('2回入力したパスワードが一致しません'), 'password');
}
/** 認証例外をキャッチ */
if ($error = $validator->run($this->request->from('name', 'password', 'mail', 'confirm'))) {
Typecho_Cookie::set('__typecho_remember_name', $this->request->name);
Typecho_Cookie::set('__typecho_remember_mail', $this->request->mail);
/** メッセージを設定 */
$this->widget('Widget_Notice')->set($error);
$this->response->goBack();
}
if(Paul_GCaptcha::check() == true){
$hasher = new PasswordHash(8, true);
$generatedPassword = Typecho_Common::randString(7);
$dataStruct = array(
'name' => $this->request->name,
'mail' => $this->request->mail,
'screenName'=> $this->request->name,
'password' => $hasher->HashPassword($generatedPassword),
'created' => $this->options->time,
'group' => 'subscriber'
);
$dataStruct = $this->pluginHandle()->register($dataStruct);
$insertId = $this->insert($dataStruct);
$this->db->fetchRow($this->select()->where('uid = ?', $insertId)
->limit(1), array($this, 'push'));
$this->pluginHandle()->finishRegister($this);
$this->user->login($this->request->name, $generatedPassword);
Typecho_Cookie::delete('__typecho_first_run');
Typecho_Cookie::delete('__typecho_remember_name');
Typecho_Cookie::delete('__typecho_remember_mail');
$this->widget('Widget_Notice')->set(_t('ユーザー <strong>%s</strong> が正常に登録されました。パスワードは <strong>%s</strong> です', $this->screenName, $generatedPassword), 'success');
$this->response->redirect($this->options->adminUrl);
}else{
$this->widget('Widget_Notice')->set(_t('認証失敗'),'error');
$this->response->goBack('?referer=' . urlencode($this->request->referer));
}
}
}
上記のフィールドを自分の SiteKey と Secert Key に置き換えます。
完了!ウェブサイトの管理画面を開いて、楽しんでください!
![5][7]
ここに dark タグを追加しました。必要に応じて [reCAPTCHA ドキュメント][8] を参照してください。
後事#
ヒント:私と同じように Handsome テーマを使用している場合、フロントエンドログインを実現するために、以下の手順を行う必要があります(Handsome テーマ以外はこのステップを行う必要はありません):::
管理画面を開き、外観設定 → 開発者設定 → カスタム出力ボディの末尾の HTML コード に以下の内容を入力します。
<script src="https://www.recaptcha.net/recaptcha/api.js" async defer></script>
次に、 /usr/themes/handsome/component/headnav.php の約 369 行の下に新しい行を追加し、以下の内容を追加します(Handsome 9.0.2)。
<div class="g-recaptcha" style="transform: scale(0.827); -webkit-transform: scale(0.827); transform-origin: 0 0; -webkit-transform-origin: 0 0;" data-sitekey="ここにあなたのSITEキーを入力してください"></div>
上記のフィールドを自分の SiteKey と Secert Key に置き換えます。
ユーザー登録が有効になっている場合は、同じファイルの約 390 行の下に新しい行を追加し、同様に以下の内容を追加します(Handsome 9.0.2)。
<div class="g-recaptcha" style="transform: scale(0.827); -webkit-transform: scale(0.827); transform-origin: 0 0; -webkit-transform-origin: 0 0;" data-sitekey="ここにあなたのSITEキーを入力してください"></div>
上記のフィールドを自分の SiteKey と Secert Key に置き換えます。
他のバージョンで行数が合わない場合や、自分で修正できない場合は、php ファイルをメールで送信して、管理者に手伝ってもらってください。
大成功!ウェブサイトからログアウトし、ホームページをリフレッシュして、楽しんでください!
展望未来#
既知の問題:Handsome フロントエンドログインの reCAPTCHA はダークモードで白のままで、現在のところ解決策はありません。皆さんのコメント欄での提案を歓迎します。
後記#
管理画面で何度もテストを行い、すべて正常です。
reCAPTCHA の管理画面にも関連記録があります。
これにより、Typecho への reCAPTCHA の導入が完了しました!
この記事は Mix Space によって xLog に同期更新されました。
元のリンクは https://blog.nekorua.com/posts/coding/26.html