Интеграция punBB и Яндекс ID

Ниже — базовый пример кода для интеграции входа через Яндекс ID (OAuth 2.0) в PunBB. Это не готовый плагин «из коробки», а скелет, который нужно встроить в PunBB (например, в отдельный файл и вызовы в нужных местах). Учитывайте, что PunBB 1.4.x написан на PHP и имеет свою систему сессий и пользователей.

Важные оговорки перед кодом

  • Нет официального плагина PunBB → Яндекс ID. Придётся писать свою обвязку.
  • Безопасность: client_secret никогда не храните в коде, который попадает в репозиторий; используйте переменные окружения.
  • Callback URL должен совпадать с тем, что указан в консоли разработчика Яндекс ID.
  • Для PunBB нужно аккуратно работать с его функциями создания/загрузки пользователя и сессиями, чтобы не сломать встроенную авторизацию.

Шаг 1: Подготовка (в админке Яндекс ID)

В консоли разработчика Яндекса:

  • Создайте приложение типа «Веб‑сервис».
  • Укажите Redirect URI, например: https://forum.rcl-radio.ru/login_yandex_callback.php.
  • Получите client_id и client_secret.

Шаг 2: Страница входа (кнопка «Войти через Яндекс»)

Пример простого файла login_yandex.php (или можно вставить кнопку в шаблон PunBB):

<?php
// login_yandex.php
require_once 'include/common.php';
require_once 'include/functions.php';

$client_id = 'ВАШ_CLIENT_ID';
$redirect_uri = urlencode('https://forum.rcl-radio.ru/login_yandex_callback.php');
$scope = urlencode('login:info'); // запрашиваем базовые данные

$auth_url = "https://oauth.yandex.ru/authorize?client_id={$client_id}&redirect_uri={$redirect_uri}&response_type=code&scope={$scope}";

header("Location: {$auth_url}");
exit;
?>

Добавьте ссылку на эту страницу в шаблон PunBB рядом с формой входа:

<a href="login_yandex.php" class="btn-yandex">Войти через Яндекс</a>

Шаг 3: Callback (обработка ответа от Яндекса)

Файл login_yandex_callback.php:

<?php
require_once 'include/common.php';
require_once 'include/functions.php';

$client_id = 'ВАШ_CLIENT_ID';
$client_secret = 'ВАШ_CLIENT_SECRET'; // лучше из env
$redirect_uri = 'https://forum.rcl-radio.ru/login_yandex_callback.php';

if (!isset($_GET['code'])) {
    // ошибка: нет кода авторизации
    message('Ошибка авторизации: нет кода от Яндекса.');
}

$code = $_GET['code'];

// Обмен кода на access_token
$token_url = 'https://oauth.yandex.ru/token';
$post_data = [
    'grant_type' => 'authorization_code',
    'code'       => $code,
    'client_id'  => $client_id,
    'client_secret' => $client_secret,
    'redirect_uri'  => $redirect_uri,
];

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $token_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
$response = curl_exec($ch);
curl_close($ch);

if (!$response) {
    message('Ошибка: не удалось получить токен от Яндекса.');
}

$token_data = json_decode($response, true);
if (!isset($token_data['access_token'])) {
    message('Ошибка: в ответе от Яндекса нет access_token.');
}

$access_token = $token_data['access_token'];

// Получение данных пользователя
$info_url = 'https://login.yandex.ru/info?format=json';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $info_url);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: OAuth {$access_token}"]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
$user_info = curl_exec($ch);
curl_close($ch);

$user_data = json_decode($user_info, true);
if (!$user_data || !isset($user_data['id'])) {
    message('Ошибка: не удалось получить данные пользователя от Яндекса.');
}

// Теперь у нас есть данные пользователя из Яндекса
// Нужно либо найти пользователя в PunBB по email/логину, либо создать нового

$yandex_id = $user_data['id'];
$email     = isset($user_data['default_email']) ? $user_data['default_email'] : '';
$login     = isset($user_data['login']) ? $user_data['login'] : 'yandex_' . $yandex_id;
$display_name = isset($user_data['display_name']) ? $user_data['display_name'] : $login;

// Ищем пользователя в PunBB
$result = $db->query("SELECT id, username FROM {$db_prefix}users WHERE email = ? OR username = ?", $email, $login);
$row = $db->fetch_row($result);

if ($row) {
    $user_id = (int)$row[0];
    // Пользователь уже есть — логиним
    punbb_login($user_id, false); // стандартная функция PunBB для входа
} else {
    // Создаём нового пользователя
    // Важно: пароль для таких пользователей можно не хранить или поставить случайный
    $password = generate_random_password(); // нужна функция генерации
    $salt = generate_salt(); // нужна функция генерации соли
    $password_hash = sha1($salt . sha1($password)); // PunBB 1.4 использует SHA1+salt

    $db->query(
        "INSERT INTO {$db_prefix}users (username, password, salt, email, disp_name, show_img, last_visit, registered, group_id) VALUES (?, ?, ?, ?, ?, 0, " . time() . ", " . time() . ", 2)",
        $login, $password_hash, $salt, $email, $display_name
    );
    $user_id = $db->insert_id();

    // Опционально: сохранить yandex_id в отдельной таблице/поле, чтобы потом не создавать дубли
}

if ($user_id) {
    punbb_login($user_id, false);
    redirect('index.php', 'Вы успешно вошли через Яндекс!');
} else {
    message('Не удалось войти или создать пользователя.');
}
?>

Примечание: функции generate_random_password(), generate_salt() и punbb_login() — это либо ваши хелперы, либо стандартные функции PunBB/вашей обвязки. В PunBB 1.4 логика хеширования пароля и создания пользователя может отличаться в разных форках/патчах, поэтому сверяйте с вашим кодом.


Как избежать дублей пользователей

Самый надёжный способ — хранить связь yandex_id → punbb_user_id в отдельной таблице, например:

CREATE TABLE pp_yandex_links (
  yandex_id VARCHAR(255) NOT NULL,
  user_id INT NOT NULL,
  PRIMARY KEY (yandex_id)
);

Тогда при входе сначала ищите по yandex_id, и только если не нашли — создавайте нового пользователя.


Интеграция с политикой конфиденциальности (галочка согласия)

Если вы хотите требовать согласие с политикой при входе через Яндекс, проще всего сделать это на отдельной странице перед редиректом на Яндекс:

  1. Пользователь нажимает «Войти через Яндекс».
  2. Его перекидывает на login_yandex_agree.php, где есть чекбокс «Нажимая „Войти через Яндекс“, вы соглашаетесь с Политикой конфиденциальности сайта».
  3. Если галочка не стоит — показать ошибку.
  4. Если стоит — записать факт согласия (в сессию или в таблицу) и редиректить на login_yandex.php.

Пример проверки чекбокса:

if (!isset($_POST['privacy_policy_accepted'])) {
    message('Вы должны согласиться с Политикой конфиденциальности для входа через Яндекс.');
}

И форма:

<form method="post" action="login_yandex.php">
    <label>
        <input type="checkbox" name="privacy_policy_accepted" value="1">
        Нажимая «Войти через Яндекс», вы соглашаетесь с <a href="/privacy.html">Политикой конфиденциальности сайта</a>.
    </label>
    <button type="submit">Продолжить вход через Яндекс</button>
</form>

Нюансы под ваш случай (PunBB 1.4.6 + префикс pp_)

  • Все запросы к базе должны использовать $db_prefix (в PunBB это глобальная переменная). Если у вас префикс pp_, то $db_prefix уже должен быть равен pp_.
  • Не меняйте структуру таблиц PunBB вручную без понимания последствий. Для связи с Яндекс ID лучше добавлять отдельную таблицу (как выше), а не менять существующие.
  • Если вы планируете в будущем переезд на bbPress, то такую интеграцию лучше делать так, чтобы её было легко отключить или перенести логику.

Что ещё важно учесть с точки зрения закона и вашего контекста

  • При регистрации через Яндекс вы собираете персональные данные (email, имя, ID). Это нужно отразить в политике конфиденциальности.
  • Если вы прекращаете регистрацию новых пользователей (по ФЗ № 199‑ФЗ), то на странице login_yandex_agree.php можно дополнительно показывать сообщение: «Регистрация новых пользователей прекращена. Вход возможен только для существующих аккаунтов».

Добавить комментарий