1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/isszz-rotate-captcha

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Это зеркальный репозиторий, синхронизируется ежедневно с исходного репозитория.
Клонировать/Скачать
Внести вклад в разработку кода
Синхронизировать код
Отмена
Подсказка: Поскольку Git не поддерживает пустые директории, создание директории приведёт к созданию пустого файла .keep.
Loading...
README.md

Сменить капчу

Сменить изображение с определённым углом поворота для проверки подлинности, используя PHP для генерации проверочных изображений (gd или imagick) для поворота проверочного изображения. Может использоваться в различных фреймворках.

Фронтенд уже поддерживает нативные JS, jquery, vue2, uniapp версии и продолжает обновляться. Можно смело использовать.

Версия для react пока не реализована, но вы можете попробовать реализовать её самостоятельно, опираясь на существующую версию.

Известно, что uniapp упаковывает приложение WeChat (iOS имеет проблемы с зависанием, надеемся, что кто-то сможет это исправить, у меня нет устройства, чтобы воспроизвести проблему).

Если вы обнаружите ошибку или у вас есть лучшие предложения, пожалуйста, сообщите об этом через issue.

Stable Version Total Downloads License

Обновления

  • 2021-09-10 Новое

    • Добавлено нативное JS-решение, оптимизирован некоторый код.
  • 2021-09-16 Новое

    • Добавлена функция хранения с использованием драйверов session, cache, cookie.
    • Метод проверки изменён на обмен токенами, что удобно для vue, react и других вызовов.
    • Способ шифрования изменён на AES.
  • 2021-09-17 Новое

    • Добавлен параметр настройки вывода, можно установить webp, создавать изображения меньшего размера, с более высоким разрешением и поддерживающие прозрачный фон.
  • 2021-09-19 Обновление

    • Удалена зависимость от thinkphp6, можно добавить небольшое количество кода в другие фреймворки.
  • 2021-09-20 Обновление

    • В токен хранения добавлен префикс.
    • Добавлен драйвер хранилища Redis, не зависящий от фреймворка, поддерживающий Redis.
  • 2021-09-22 Обновление

    • Добавлена версия для uniapp, в настоящее время существует проблема с версией для ПК.
  • 2021-09-23 Обновление

    • Добавлена версия vue, основанная на vue2, не протестирована с vue3.
  • 2021-09-24 Обновление

    • Исправлена проблема с зависанием приложения uniapp на Android (проблема с iOS всё ещё существует, поскольку у меня нет оборудования для тестирования, пока невозможно исправить).
  • 2021-09-25 Обновление

    • Версия vue получила поддержку событий касания, совместима с h5.
  • 2021-09-26 Обновление

    • Версия Vue изменена на canvas.
  • 2021-10-07 Обновление

    • Исправлено вращение угла с помощью Imagick.
    • Исправлены логические ошибки в старом способе хранения, после одного месяца невозможно найти изображение с тем же углом.
    • Добавлен переключатель для сохранения изображений, при повторном создании изображения с тем же углом можно получить его обратно без повторного создания.
    • При включении сохранения изображений можно настроить глубину хранения, storeImage со значением true или 1 сохраняет изображения в папке с углом, значение 2 создаёт две папки в зависимости от угла, а значение больше 2 создаёт три папки.
    • Если сохранение изображений отключено, все файлы в каталоге текущего доступного изображения будут удалены после доступа к изображению.
  • 2021-10-20 Обновление

    • Язык перемещён в раздел конфигурации.
  • 2022-01-05 Обновление

    • Добавлены комментарии фасада.
    • Удалён метод rotate_captcha_img из класса помощника, вместо него используется rotate_captcha_output, который работает аналогично \isszz\captcha\rotate\facade\Captcha::output и возвращает массив [$mime, $image], содержащий тип MIME и содержимое изображения.
  • 2022-09-12 Обновление

    • Добавлено объяснение отсутствия поддержки thinkphp6.
    • Проблема с обработкой событий в нативном JS исправлена (спасибо за issue от 笨笨天才).
    • Изменено описание проблемы с заглавными буквами X-CaptchaToken в Linux, которые нельзя получить, следует использовать X-Captchatoken (спасибо за issue от 笨笨天才). Данный текст написан на языке PHP.

Используется для тестирования, эта часть может самостоятельно загружать весь материал из библиотеки в базу данных или кэш, в общем, очень гибко.

$list = [
    '1.png',
    '2.png',
    '1.jpg',
    '2.jpg',
    '3.jpg',
    '4.jpg',
    '5.jpg',
    '6.jpg',
    '7.jpg',
    '8.jpg',
    '9.jpg',
];

// upload_path нужно написать самому

// Случайно взять одно изображение
$key = array_rand($list, 1);
if (isset($list[$key])) {
    // Взять изображение из каталога хранения материалов
    $image = upload_path('captcha_mtl') . $list[$key];  
}

Примечание: метод upload_path — это пользовательский метод, который зависит от используемого вами фреймворка и позволяет получить корневой каталог, где хранятся ваши материалы. Например, в фреймворке TP6 можно написать так:

function upload_path(string $path = ''): string
{
    return public_path(DIRECTORY_SEPARATOR .'uploads' . DIRECTORY_SEPARATOR . ($path ? ltrim($path, DIRECTORY_SEPARATOR) : $path));
}

Новое: из указанного каталога случайным образом считывает файл. Неизвестна эффективность этого метода, он основан на классе FilesystemIterator.

$image = File::make(upload_path('captcha_mtl'))->rand();

Создаёт изображение для проверки.

// Устанавливает язык
$rotateCaptcha = RotateCaptcha::setLang('zh-cn');
$rotateCaptcha->create(...);

$data = RotateCaptcha::create(
    $image,
    upload_path('captcha') // Используется для хранения сгенерированного изображения
)->get(260); // 260 — конечный размер сгенерированного изображения.

if (!$data) {
    $this->result(1, 'error');
}

// $data['str'] — путь к изображению с шифрованием, используется для обмена изображениями проверки на стороне клиента
// Здесь клиент не участвует в получении угла, всё отправляется на сервер для проверки
// Можно использовать заголовок для передачи токена X-Captchatoken
$this->result(0, 'success', ['str' => $data['str']], ['X-Captchatoken' => $data['token']]);

Проверка

public function verify(Request $request)
{
    $angle = $request->get('angle');
    // Предпочитает получать токен из заголовка
    $token = $request->header('X-Captchatoken') ?: $request->get('token');

    if (empty($token) || empty($angle)) {
        $this->result(1, 'error');
    }

    try {
        if (RotateCaptcha::check($token, $angle) === true) {
            $this->result(0, 'success');
        }
    } catch (CaptchaException $e) {
        $this->result(1, $e->getMessage());
    }

    $this->result(1, 'error');
}

Отображение изображения через клиент

public function img(Request $request)
{
    $str = $request->get('id');

    [$mime, $image] = RotateCaptcha::output($str, upload_path('captcha'));

    if (empty($image)) {
        return '';
    }

    return response($image, 200, [
        'Cache-Control' => 'private, no-cache, no-store, must-revalidate',
        'Content-Type' => $mime,
        'Content-Length' => strlen($image)
    ]);
}

Возврат JSON

public function result(int|string $code = 0, string $msg = 'success', array|string $data, array $header = [])
{
    $result = [
        'code' => $code,
        'data' => $data,
        'msg' => lang($msg) ?: ($code > 0 ? 'error' : 'success'),
    ];

    $response = Response::create($result, 'json')->code(200);

    if (!empty($header)) {
        $response = $response->header($header);
    }
    throw new \think\exception\HttpResponseException($response);
}
``` 10.jpg,  
11.jpg,  
12.jpg,  
13.jpg;

$key = array_rand($list, 1);

if (isset($list[$key])) {
    $image = $list[$key];
}

$image = path('upload') . 'captcha_mtl' . DIRECTORY_SEPARATOR . $image;

// 新增: 从指定目录随机读取文件,这个方法不知道效率如何,基于FilesystemIterator类实现
$image = File::make(path('upload') . 'captcha_mtl' . DIRECTORY_SEPARATOR)->rand();

$data = Captcha::configDrive(\CaptchaConfig::class)->create($image, path('upload') . 'captcha' . DIRECTORY_SEPARATOR)->get(260);

header('Content-Type:application/json; charset=utf-8');

if ($data) {
    // 可以使用header传递token
    header('X-CaptchaToken: '. $data['token']);
    echo json_encode([
        'code' => 0,
        'msg' => 'success',
        'data' => [/*'token' => $data['token'], */'str' => $data['str']],
    ]);
}

echo json_encode([
    'code' => 1,
    'msg' => 'error',
    'data' => null,
]);

非thinkphp6框架,验证


use isszz\captcha\rotate\support\request\Request;
use isszz\captcha\rotate\CaptchaException;
use isszz\captcha\rotate\facade\Captcha;

class CaptchaConfig extends \isszz\captcha\rotate\Config
{
    public function get(string $name, string $defaultValue = null): mixed
    {
        return \Config::get($name, $defaultValue);
    }

    public function put(string $name, array|string $data): bool
    {
        return \Config::put($name, $data);
    }

    public function forget(string $name): bool
    {
        return \Config::forget($name);
    }
}

$angle = $_GET['angle'] ?? '';

// 优先从header获取token
$token = Request::header('X-Captchatoken') ?: $_GET['token'] ?? '';

if(empty($token) || empty($angle)) {
    exit(json_encode(['code' => 1, 'msg' => 'error']));
}

try {
    if(Captcha::configDrive(\CaptchaConfig::class)->setLang('zh-cn')->check($token, $angle) === true) {
        exit(json_encode(['code' => 0, 'msg' => 'success']));
    }
} catch(CaptchaException $e) {
    exit(json_encode(['code' => 1, 'msg' => $e->getMessage()]));
}

exit(json_encode(['code' => 1, 'msg' => 'error']));

非thinkphp6框架,输出图片

<?php

use isszz\captcha\rotate\facade\Captcha;

$id = $_GET['id'] ?? null;

if(empty($id)) {
    exit('');
}

[$mime, $image] = Captcha::output($id, upload_path('captcha'));

if(empty($image)) {
    exit('');
}

header('Cache-Control: private, no-cache, no-store, must-revalidate');
// header('Content-Disposition: inline; filename=captcha_' . $id . '.' . str_replace('image/', '.', $mime));
header('Content-type: '. $mime);
header('Content-Length: '. strlen($image));
echo $image;

О конфигурации драйвера и пользовательском драйвере хранения


use isszz\captcha\rotate\Store;
use isszz\captcha\rotate\Config;

class CaptchaConfig extends Config
{
    public function get(string $name, string $defaultValue = null): mixed
    {
        // 获取配置
        return Config::get($name, $defaultValue);
    }

    public function put(string $name, array|string $data): bool
    {
        // 存储配置 - 暂时无用
        return Config::put($name, $data);
    }

    public function forget(string $name): bool
    {
        // 删除配置 - 暂时无用
        return Config::forget($name);
    }
}

class CaptchaSessionStore extends Store
{
    public function get(string $token): array
    {
        if(!Session::has($token)) {
            return [];
        }
        
        $payload = Session::get($token);

        if(empty($payload)) {
            return [];
        }

        $payload = $this->encrypter->decrypt($payload);

        if(empty($payload)) {
            return [];
        }

        Session::forget($token);

        return json_decode($payload, true);
    }

    public function put(?int $degrees): string
    {
        [$token, $payload] = $this->buildPayload($degrees);

        // 存储token, 并设置token过期时间ttl

``` **Сессия::put($token, $payload, $this->ttl);**

    **return $token;**
}

Это язык PHP.

Передняя конфигурация:

options = {
    theme: '#07f', // Основной цвет проверки
    title: 'Безопасная проверка',
    desc: 'Перетащите ползунок, чтобы угол изображения был правильным',
    width: 305, // Ширина окна проверки
    successClose: 1500, // Время закрытия страницы после успешной проверки
    timerProgressBar: !0, // Отображать ли индикатор выполнения после успешной проверки
    timerProgressBarColor: '#07f', // Цвет индикатора выполнения
    url: {
        info: '/captcha', // Получить информацию о проверке
        check: '/captcha/check', // Проверить
        img: '/captcha/img', // Заменить изображение
    },
    init: function (captcha) {}, // Инициализация
    success: function () {}, // Проверка успешна
    fail: function () {}, // Проверка не удалась
    complete: function (state) {}, // Вызвать проверку, независимо от успеха или неудачи
    close: function (state) {} // Закрыть окно проверки и вернуть состояние проверки state
};

Использование на передней части:

Использование версии JavaScript

// .J__captcha__ — это контейнер для вывода проверки
// Способ 1
let myCaptcha = document.querySelectorAll('.J__captcha__').item(0).captcha({
    // Что показывать при успешной проверке
    timerProgressBar: !0, // Использовать ли индикатор выполнения
    timerProgressBarColor: '#07f', // Цвет индикатора выполнения
    url: {
        create: '/common/captcha/rotate', // Получить информацию о проверке
        check: '/common/captcha/verify', // Проверить
        img: '/common/captcha/img' // Заменить изображение
    },
    // Обратный вызов инициализации
    init: function (captcha) {
        // console.log(captcha);
    },
    // Успешный обратный вызов
    success: function() {
        console.log('Состояние проверки Captcha: успешно');
    },
    // Неудачный обратный вызов
    fail: function() {
        console.log('Состояние проверки Captcha: неудачно');
    },
    // Вызов проверки обратного вызова, независимо от успеха или неудачи
    complete: function(state) {
        console.log('Проверка Captcha завершена, состояние: ', state);
    },
    // Триггер проверки закрытия (необходимо закрыть после успешной проверки)
    close: function(state) {
        modal.close(); // Закрыть ваш modal
        console.log('Закрыть проверку Captcha, состояние: ', state);
    }
});
// Способ 2
let myCaptcha = new Captcha(document.querySelectorAll('.J__captcha__').item(0), {
    // options аналогично...
});

Пример использования jQuery

// .J__captcha__ - это контейнер для вывода проверки
modal.element.find('.J__captcha__').captcha({
    // options аналогично...
});
// Получить экземпляр Captcha
// var captcha = modal.element.find('.J__captcha__').data('captcha');
// console.log(captcha.state());

Пример использования Vue

<template>
    <div id="app">
        <div @click="openCaptcha">
            <img alt="Vue logo" src="./assets/logo.png">
            <div>Открыть проверку</div>
        </div>
        <RoutateCaptcha :options="captchaOptions" v-if="captchaShow" @close="captchaShow = false" @init="captchaInit" @complete="captchaComplete" @success="captchaSuccess" @fail="captchaFail"></RoutateCaptcha>
    </div>
</template>

<script>
// Путь к компоненту, здесь импортировать. Расположение компонента: js/vue/RoutateCaptcha
import RoutateCaptcha from './components/RoutateCaptcha/index.vue'

export default {
    name: 'captchaDemo',
    components: {
        RoutateCaptcha
    },
    data() {
        return {
            captchaShow: false,
            captchaOptions: {
                theme: '#07f',
                title: 'Безопасный чек',
                desc: 'Перетащить ползунок, чтобы сделать угол изображения правильным',
                successClose: 1500, // время закрытия страницы после успешного чека
                timerProgressBar: true, // отображать ли индикатор прогресса после успешного чека
                timerProgressBarColor: 'rgba(0, 0, 0, 0.2)',
                request: {
                    // получить информацию о чеке
                    info: (callback) => {
                        this.getJSON('http://vmd.co/common/captcha/rotate', null, function(res, xhr) {
                            if(xhr.status != 200) {
                                alert('Система ошибка: '+ res.statusCode +', пожалуйста, закройте и попробуйте снова!');
                                return false
                            }
                            // Второй параметр передает токен из заголовка, если вам неудобно, вы можете вернуть токен в res
                            callback(res, xhr.getResponseHeader('X-CaptchaToken'))
                        })
                    },
                    // проверка, угол пользовательского вращения
                    check: (angle, token, callback) => {
                        // Установите токен хорошо, данные проверки передаются на серверную часть
                        // Конечно, этот запрос данных только для справки, фактическое использование должно соответствовать вашему собственному запросу данных
                        this.token = token
                        this.getJSON('http://vmd.co/common/captcha/verify', {angle: angle}, function(res, xhr) {
                            if(xhr.status != 200) {
                                alert('Системная ошибка: '+
``` Данный фрагмент представляет собой код на языке Vue.js, который описывает компонент для отображения и проверки капчи в приложении на платформе uniapp.

В коде описывается компонент с именем «rotate-captcha», который отображает вращающуюся капчу и предоставляет методы для взаимодействия с ней. Компонент принимает несколько параметров:
* «options» — объект с настройками капча (например, тема, заголовок, описание, время ожидания после успешной проверки и т. д.);
* «init» — функция, которая вызывается при инициализации капча;
* «close» — функция, вызываемая при закрытии капча;
* «complete» — функция, вызываемая после завершения проверки капча;
* «success» — функция, вызываемая в случае успешной проверки капча;
* «fail» — функция, вызываемая в случае неудачной проверки капча.

Компонент также содержит методы «captchaInit», «captchaSuccess», «captchaFail», которые вызываются при соответствующих событиях.

Код не содержит информации о том, как именно работает капча, но описывает её внешний вид и поведение.

Комментарии ( 0 )

Вы можете оставить комментарий после Вход в систему

Введение

Описание недоступно Развернуть Свернуть
JavaScript и 4 других языков
MIT
Отмена

Обновления

Пока нет обновлений

Участники

все

Недавние действия

Загрузить больше
Больше нет результатов для загрузки
1
https://gitlife.ru/oschina-mirror/isszz-rotate-captcha.git
git@gitlife.ru:oschina-mirror/isszz-rotate-captcha.git
oschina-mirror
isszz-rotate-captcha
isszz-rotate-captcha
main