Ссылку обнови на я.д пожалуйстаНа форуме есть очень много тем с авторизацией на форуме Xenforo, но большая часть из них имеет в себе те или иные недочете в коде и в алгоритмах получения данных о пользователе. Сегодня я постараюсь подробно расписать процесс привязки вашего приложения к сайту с использованием Xenforo API 2.1+. Код будет написан на C#, но при желании его можно переделать под C++ и других современных языков программирования.
1. Получаем ключ API для форума.
Для нормальной работы с api форума нам нужен соответствующий ключ, который можно создать в админ-панеле. В параметрах найдите вкладку "Ключи API" и откройте ее. Если пункт не появляется, то, скорее всего, у вас отключен api в конфиге форума. Это исправляется изменением строки$config['enableApi'] = false;
на$config['enableApi'] = true;
.
Создайте новый ключ API с настройками, как на следующем скриншоте:
При желании можно добавить еще несколько разрешенных областей, если вы уверены, что это не навредит безопасности проекта.![]()
2. Пишем wrapper для API.
Для начала стоит проверить работоспособность api форума. По умолчанию эндроинты располагаются по пути http(s)://yourforum.com/api/endpoint, но если у вас не настроены friendly URLs, то скорее всего это http(s)://yourforum.com/index.php?api/endpoint. Для первых тестов советую использовать бесплатную программуПожалуйста, авторизуйтесь для просмотра ссылки., либо онлайн-сервисПожалуйста, авторизуйтесь для просмотра ссылки.. Нам нужно послать POST запрос на api/auth, указав в параметрах запроса наш логин (почту или юзернейм) и пароль. Также в заголовки необходимо добавитьXF-Api-Key: Ваш ключ
. Так сказано на официальном сайте Xenforo, и без этих данный сервер будет возвращать ошибку.
Если вы все сделали правильно, то в окне response должен массив данных в формате JSON. Вот пример ответа от моего сервера:
Многие авторы статей на нашем форуме на этом этапе обычно приступают к написанию клиента, который будет отправлять запросы по шаблону от Xenforo. Но я не советую так делать. Как-никак, в заголовках запроса участвует суперключ api форума, который может позволить злоумышленникам брутить пароли пользователей, либо использовать другие его важные методы, которые включены в админ-панеле. Хорошим решением будет использование дополнительной PHP страницы, которая послужит нам посредником в "отношениях" с сервером.JSON:{ "success": true, "user": { "about": "", "activity_visible": true, "alert_optout": [], "allow_post_profile": "members", "allow_receive_news_feed": "everyone", "allow_send_personal_conversation": "members", "allow_view_identities": "everyone", "allow_view_profile": "everyone", "avatar_urls": { "o": null, "h": null, "l": null, "m": null, "s": null }, "can_ban": false, "can_converse": false, "can_edit": false, "can_follow": false, "can_ignore": false, "can_post_profile": false, "can_view_profile": true, "can_view_profile_posts": true, "can_warn": false, "content_show_signature": true, "creation_watch_state": "watch_no_email", "custom_fields": { "skype": "", "facebook": "", "twitter": "" }, "custom_title": "", "email": "mysuperemail@mail.ru", "email_on_conversation": false, "gravatar": "", "interaction_watch_state": "watch_no_email", "is_admin": false, "is_discouraged": false, "is_moderator": false, "is_staff": false, "is_super_admin": false, "last_activity": 1624800266, "location": "", "message_count": 0, "push_on_conversation": false, "push_optout": [], "reaction_score": 0, "receive_admin_email": false, "register_date": 1624788945, "secondary_group_ids": [], "show_dob_date": false, "show_dob_year": false, "signature": "", "timezone": "Europe/Moscow", "trophy_points": 0, "usa_tfa": false, "user_group_id": 5, "user_id": 5, "user_state": "valid", "user_title": "Customer", "username": "TestUser", "visible": true, "website": "" } }
Вот простой код с использованием cURL. Можно было воспользоваться стандартными средствави PHP, но на моем хостинге, к сожалению, это не очень хотело работать.
Теперь нужно загрузить файл на наш хостинг и проверить его работоспособность с помощью вышеупомянутых сервисов. На этот раз достаточно указать только login и password.PHP:<?php $url = "http://yourforum.com/api/auth"; $post_data = array ( 'login' => $_POST["login"], 'password' => $_POST["password"], ); if (!isset($_POST["login"]) && !isset($_POST["password"])) $post_data = array(); if (isset($_POST["login"]) && !isset($_POST["password"])) $post_data = array('login' => $_POST["login"]); if (!isset($_POST["login"]) && isset($_POST["password"])) $post_data = array('password' => $_POST["password"]); $ch = curl_init(); curl_setopt($ch, CURLOPT_HTTPHEADER, array( 'Accept: application/json', 'XF-Api-Key: Ключ API' )); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data); $output = curl_exec($ch); curl_close($ch); echo $output; ?>
3.1. Написание классов для нашего лоадера.
Для начала стоит позаботиться о правильной десериализации ответа от нашего сервера. Поскольку мы работаем с форматом данных JSON, нам необходимо написать класс, с помощью которого можно спарсить всю неоюходимую информацию. Очень легко это можно сделать с помощью программы, которую я выкладывал около полугода назад - https://yougame.biz/threads/173834/. Выходной файл нужно лишь немного подрежактировать, добавив поддержку отображения ошибок.
Конкретно мой класс можно скачать с пастбина:Пожалуйста, авторизуйтесь для просмотра ссылки..
В принципе, на этом можно было перейти к написанию основного кода, но я считаю правильным добавить сохранение авторизационных данных в реестр компьютера. Конечно, можно было это сделать через дополнительный файл или настройки Settings.settings, но работа с реестром будет гораздо более надежной из-за отсутствия привязки к расположению файла.
Создавать ключ я советую в разделе HKEY_CURRENT_USER, но можете воспользоваться и HKEY_LOCAL_MACHINE, если хотите избавиться от привязки к пользователю компьютера.C#:using Microsoft.Win32; using System; namespace XenforoLoader { class Session { public string login { get; private set; } public string password { get; private set; } public void LoadData() { RegistryKey directory = Registry.CurrentUser.CreateSubKey("SuperiorLoader"); login = (string)directory.GetValue("login"); password = (string)directory.GetValue("password"); directory.Close(); } public void SaveData(string newLogin, string newPassword) { login = newLogin; password = newPassword; RegistryKey directory = Registry.CurrentUser.CreateSubKey("SuperiorLoader"); directory.SetValue("login", login); directory.SetValue("password", password); directory.Close(); } public void ClearData() { login = null; password = null; RegistryKey directory = Registry.CurrentUser.CreateSubKey("SuperiorLoader"); directory.SetValue("login", ""); directory.SetValue("password", ""); directory.Close(); } public bool isAuthed() { return !String.IsNullOrEmpty(login) && !String.IsNullOrEmpty(password); } public Session() { LoadData(); } } }
3.2. Написание основной части программы.
Мне не очень хочется заострять внимание на каждой мелочи в коде, поэтому я просто добавлю комментарии к основным моментам в программе:
Скриншоты работы программы:C#:using System; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Text; using Newtonsoft.Json; using System.Threading; namespace XenforoLoader { class Program { static void Main(string[] args) { // Устанавливаем заголовок консоли и выводим логотип нашего лоадера. Console.Title = "Loader"; Console.WriteLine(@" _ _ _____ "); Console.WriteLine(@"| | | |___ | "); Console.WriteLine(@"| | ___ __ _ __| | / / _ __"); Console.WriteLine(@"| | / _ \ / _` |/ _` | \ \| '__/"); Console.WriteLine(@"| |___| (_) | (_| | (_| | __) | |"); Console.WriteLine(@"\_____|\___/ \__,_|\__,_|\____/|_|"); Console.WriteLine("\nyougame.biz | vk.com/ugame | t.me/govthing\n\n"); // Объявляем переменные с данными о пользователе и сохраненной "сессии". Мы прописали в конструкторе выгрузку данных из реестра, поэтому нет необхомости писать session.LoadData(); User user = null; Session session = new Session(); // Фактически, мы проверяем строки с логином и паролем на пустоту. if (session.isAuthed()) { Console.WriteLine("Saved data found. Trying to log in..."); string resp = POST("http://irval.yourforum.com/auth.php", $"login={session.login}&password={session.password}"); // Отправляем POST запрос на наш wrapper. Response response = JsonConvert.DeserializeObject<Response>(resp); // Десериализация ответа. if (response.success == true) // Если success == null, то запрос не удался и мы выведем текст ошибки. user = response.User; // Заносим данные об авторизированном пользователе в user. else { Console.WriteLine("Cannot auth with saved credentials: " + response.errors.First().message); session.ClearData(); Process.Start(Assembly.GetEntryAssembly().Location); // Перезапуск приложения. Process.GetCurrentProcess().Kill(); } } else { string login, password; Console.Write("[>] Enter username or email: "); login = Console.ReadLine(); Console.Write("[>] Enter password: "); password = Console.ReadLine(); string resp = POST("http://irval.yourforum.com/auth.php", $"login={login}&password={password}"); // POST запрос на наш wrapper. См. строки 34-45. Response response = JsonConvert.DeserializeObject<Response>(resp); if (response.success == true) { user = response.User; session.SaveData(login, password); // Записываем данные пользователя в реестр. } else Console.WriteLine("Cannot auth with entered credentials: " + response.errors.First().message); } if (user == null) // Если мы не передали значение user, т.е. авторизация не удалась. { Console.ReadKey(); // Читаем один символ, после чего закрываем процесс. Process.GetCurrentProcess().Kill(); } Console.WriteLine("You have successfully logged in."); Console.Title = $"Loader [{user.username}]"; // Добавлем имя пользователя в заголовок. Thread.Sleep(1500); Console.Clear(); Console.WriteLine("Current user information:\n"); // Выводим некоторую информацию о пользователе Xenforo. Console.WriteLine($"Username: {user.username}\nEmail: {user.email}\nisStaff: {user.is_staff}\nisBanned: {user.is_banned}"); string secondaryGroups = user.secondary_group_ids != null && user.secondary_group_ids.Count > 0 ? String.Join(", ", user.secondary_group_ids) : "No groups"; Console.WriteLine($"MainGroup: {user.user_group_id}\nSecondaryGroups: {secondaryGroups}\nAvatar: {user.avatar_urls.m ?? "null"}"); Console.Write("\n\nPress Delete to unlogin or any key to exit..."); if (Console.ReadKey().Key == ConsoleKey.Delete) // Прроверка на нажатие Delete. { session.ClearData(); // Очищаем строки в реестре. Console.WriteLine("\nSuccessfully logged out."); Thread.Sleep(2500); } Process.GetCurrentProcess().Kill(); } private static string POST(string Url, string Data) // Функция POST запроса. { try { System.Net.WebRequest req = System.Net.WebRequest.Create(Url); req.Method = "POST"; req.Timeout = 100000; req.ContentType = "application/x-www-form-urlencoded"; byte[] sentData = Encoding.GetEncoding(1251).GetBytes(Data); req.ContentLength = sentData.Length; System.IO.Stream sendStream = req.GetRequestStream(); sendStream.Write(sentData, 0, sentData.Length); sendStream.Close(); System.Net.WebResponse res = req.GetResponse(); System.IO.Stream ReceiveStream = res.GetResponseStream(); System.IO.StreamReader sr = new System.IO.StreamReader(ReceiveStream, Encoding.UTF8); //Кодировка указывается в зависимости от кодировки ответа сервера Char[] read = new Char[256]; int count = sr.Read(read, 0, 256); string Out = String.Empty; while (count > 0) { String str = new String(read, 0, count); Out += str; count = sr.Read(read, 0, 256); } return Out; } catch (Exception ex) { File.WriteAllText("crash.log", ex.Message); // Пишем лог-файл с ошибкой запроса. return null; } } } }
Скачать готовые исходники клиента можно здесь:Пожалуйста, авторизуйтесь для просмотра ссылки..
Отдельное спасибо HORMAN за предоставленный форум, на котором мы еще будем делать много интересного :)
Обновил.Ссылку обнови на я.д пожалуйста
Проект предоставляет различный материал, относящийся к сфере киберспорта, программирования, ПО для игр, а также позволяет его участникам общаться на многие другие темы. Почта для жалоб: admin@yougame.biz