Веб-сайт предлагает вам отсканировать код WeChat для входа в систему. Как они это реализуют?
Веб-сайт предлагает вам отсканировать код WeChat для входа в систему. Как они это реализуют?

Всем привет, я Брат Фу, мастер технического УП.

Как технический программист, при использовании сообществ, форумов или различных сервисов искусственного интеллекта я часто вижу такое приглашение: «Используйте официальную учетную запись WeChat, чтобы отсканировать QR-код для входа». Это связано с тем, что помимо входа в систему этот метод входа также может позволить пользователям накапливать данные в официальной учетной записи и получать повышение от официальной учетной записи в будущем, что, можно сказать, убивает двух зайцев одним выстрелом. Итак, как это делается? 🤔

Брат Фу, позвольте мне сначала привести вам пример такого входа в систему, чтобы каждый мог ознакомиться с этим бизнес-сценарием.

Посредством такого отображения эффекта страницы мы можем примерно знать, что непрерывное обнаружение пользовательских страниц с помощью checkScan требует использования уникального значения идентификатора. Когда пользователь сканирует код с помощью WeChat, уникальное значение идентификатора может быть получено и сохранено через официальную учетную запись WeChat, и создается связь между уникальным идентификатором и токеном. Затем, когда checkScan просканирует и обнаружит, что на сервере есть такое сопоставление, токен можно будет получить и сохранить в браузере, что позволит пользователю успешно войти в систему.

Процесс такой, как же обрабатывается конкретная реализация кода? Далее брат Фу расскажет вам, как реализовать этот план.

В конце статьи мы предоставляем метод скидки «Planet: Coders Club Lock»🧧, чтобы присоединиться.,и этот курсизкодовый адрес。Демонстрационный адрес проекта:https://gaga.plus - 8 практических проектов

1. Проектирование процесса

Процесс входа в систему при сканировании кода WeChat в основном состоит из четырех частей: пользователя, браузера, внутренней службы и официальной учетной записи. Сначала мы можем понять всю взаимосвязь вызовов с помощью блок-схемы UML.

  • первый,Действие Авторизоваться инициируется пользователем. Пусть WEB-страница от Служить закончит получать Авторизоваться сертификат.
  • после,После получения главной страницы Авторизоваться Сертификат,Можетиспользовать Ticket от Официальный аккаунт Служить платформе в обмен на QR-код.
  • Наконец, пользователь Сканируйте код, чтобы войти. После сканирования кода терминал Служить получит сообщение от Официального лица. аккаунтиз сообщения обратного вызова, сторона Служить получит сообщение обратного вызова из openid [уникальный идентификатор пользователя] и ticket Сделайте привязку. В это время вы также можете создать jwt token Обратная связь с фронтендом, как Авторизоваться успешное хранение информации, последующая проверка jwt token Вот и все.

При таком понимании процесса далее мы можем посмотреть, как реализуется код.

2. Документы для стыковки - Официальная платформа аккаунта

  • Вичат Официальный аккаунттестовая платформа:https://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index - Нет необходимости подавать заявку на официальное аккаунт может завершить тест, как в песочнице
  • получать Access Token Документация: https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html.
  • Сгенерируйте QR-код с параметрами: https://developers.weixin.qq.com/doc/offiaccount/Account_Management/Generating_a_Parametric_QR_Code.html - Наконец, это QR-код, сканируемый пользователем.
  • проникновение в инструмент для интранета, natapp.cn - Потому что необходимо позволить Официальному аккаунт Позвоните в местныйиз Служить,Что необходимо, так это сопоставить ваш из Служить с общедоступной сетью. Примечание. Вы должны выбрать оплату в размере 12 юаней.,В противном случае подключение невозможно.

3. Реализация функции

Брат Фу усыновил его здесь DDD На основе структуры инженерной модели мы разработали сервер входа в систему с кодом сканирования общедоступной учетной записи. если ты прав DDD Если вы еще не знакомы с ним, вы можете прочитать серию, написанную Братом Фу. DDD Учебник "Ява"; Краткое руководство》-> bugstack.cn -> дорожная книга

1. Инженерная конструкция

  • xfg-dev-tech-app Это точка входа приложения запуска, другие модули также вводятся прямо или косвенно из app модуль, чтобы его можно было Spring Сканируйте для загрузки.
  • xfg-dev-tech-infrastructure Это уровень инфраструктуры, используемый для подключения внешнего контента, кэшей, баз данных и другого связанного контента. Этот раздел в основном посвящен стыковке платформы разработки Вичат с интерфейсом. Принять из retrofit2 Техническая основа, делающая стыковку более удобной.
  • xfg-dev-tech-domain Это уровень реализации функции, такой как конкретная реализация Авторизоватьсяиз, которая domain Реализовано на уровне домена. ты будешь использовать в будущем DDD Другие функции также размещены в domain Каждая функция, реализованная в предметной области, представляет собой модуль.
  • xfg-dev-tech-types используется для определения основных типов, перечислений, кодов ошибок и т. д.

2. Получите QR-код.

Прочитав документы официального сайта WeChat, мы можем узнать, что для получения QR-кода для сканирования и входа в систему необходимо выполнить три шага;

  1. Первыйполучать AccessToken,это Официальный аккаунтиз Глобально уникальный интерфейс для вызова учетных данных, Официальный аккаунт требует использовать access_token при вызове каждого интерфейса.
  2. проходить AccessToken получать ticket сертификат, сертификат используется для подключения пользователей Сканируйте код, чтобы войтии Официальный аккаунт После обратного звонкаполучатьсертификат,Свяжите пользователей с этим Авторизоватьсяинформация。
  3. проходить ticket Адрес доступа к внешней странице передается во внешний интерфейс напрямую: QR-код。
2.1 Стыковка интерфейсов – модернизация2
Язык кода:javascript
копировать
public interface IWeixinApiService {

    /**
     * получать Access token
     * документ:<a href="https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html">Get_access_token</a>
     *
     * @param grantType получатьaccess_tokenзаполнятьclient_credential     * @param appId     Сертификат только для сторонних пользователей
     * @param appSecret Сертификат только для сторонних пользователейключ,Прямо сейчасappsecret
     * @return результат ответа
     */
    @GET("cgi-bin/token")
    Call<WeixinTokenResponseDTO> getToken(
            @Query("grant_type") String grantType,
            @Query("appid") String appId,
            @Query("secret") String appSecret
    );

    /**
     * получать Реквизиты для входа ticket
     * документ:<a href="https://developers.weixin.qq.com/doc/offiaccount/Account_Management/Generating_a_Parametric_QR_Code.html">Generating_a_Parametric_QR_Code</a>
     * <a href="https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=TICKET">Передняя часть на основесертификат Показать QR-код</a>
     *
     * @param accessToken            getToken получатьиз token информация
     * @param weixinQrCodeRequestDTO Объект входного параметра
     * @return результат ответа
     */
    @POST("cgi-bin/qrcode/create")
    Call<WeixinQrCodeResponseDTO> createQrCode(@Query("access_token") String accessToken, @Body WeixinQrCodeRequestDTO weixinQrCodeRequestDTO);

}
  • использовать retrofit2 Интерфейс стыковки, он может быть основан на объектно-ориентированном мышлении. HTTP интерфейса, избавляя от необходимости самостоятельно заниматься промежуточным процессом стыковки.
  • кроме того okhttp3 Стыковка рам также очень проста в использовании и при необходимости может использоваться вместе.
Язык кода:javascript
копировать
@Slf4j
@Configuration
public class Retrofit2Config {

    private static final String BASE_URL = "https://api.weixin.qq.com/";

    @Bean
    public Retrofit retrofit() {
        return new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(JacksonConverterFactory.create())
                .build();
    }

    @Bean
    public IWeixinApiService weixinApiService(Retrofit retrofit) {
        return retrofit.create(IWeixinApiService.class);
    }

}
  • использовать retrofit2 После разработки интерфейса, затем xfg-dev-tech-app Модульный config папку, создайте Служить. 【Это немного похоже на MyBatis из Dao Интерфейс тот же, вам просто нужно определить интерфейс】
2.2 Запрос ApiPost

интерфейс:https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=TICKET

  • APIPost Смоделируйте веб-страницу, чтобы получить из Сканируйте код, чтобы введитеиз QR-код.
  • Далее, когда программа придет на тестирование, она сгенерирует ticket Будет помещен сюда для имитации использования.

3. Разработка кода входа

Исходный код:cn.bugstack.xfg.dev.tech.trigger.http.LoginController

Язык кода:javascript
копировать
@Slf4j
@RestController()
@CrossOrigin("*")
@RequestMapping("/api/v1/login/")
public class LoginController {

    @Resource
    private ILoginService loginService;

    @RequestMapping(value = "weixin_qrcode_ticket", method = RequestMethod.GET)
    public Response<String> weixinQrCodeTicket() {
        try {
            String qrCodeTicket = loginService.createQrCodeTicket();
            log.info("Сгенерировать Вичат Сканируйте код, чтобы войти ticket {}", qrCodeTicket);
            return Response.<String>builder()
                    .code(Constants.ResponseCode.SUCCESS.getCode())
                    .info(Constants.ResponseCode.SUCCESS.getInfo())
                    .data(qrCodeTicket)
                    .build();
        } catch (Exception e) {
            log.info("Сгенерировать Вичат Сканируйте код, чтобы войти ticket неудача", e);
            return Response.<String>builder()
                    .code(Constants.ResponseCode.UN_ERROR.getCode())
                    .info(Constants.ResponseCode.UN_ERROR.getInfo())
                    .build();
        }
    }

    @RequestMapping(value = "check_login", method = RequestMethod.GET)
    public Response<String> checkLogin(@RequestParam String ticket) {
        try {
            String openidToken = loginService.checkLogin(ticket);
            log.info("Результаты сканирования Авторизоваться ticket:{} openidToken:{}", ticket, openidToken);
            if (StringUtils.isNotBlank(openidToken)) {
                return Response.<String>builder()
                        .code(Constants.ResponseCode.SUCCESS.getCode())
                        .info(Constants.ResponseCode.SUCCESS.getInfo())
                        .data(openidToken)
                        .build();
            } else {
                return Response.<String>builder()
                        .code(Constants.ResponseCode.NO_LOGIN.getCode())
                        .info(Constants.ResponseCode.NO_LOGIN.getInfo())
                        .build();
            }
        } catch (Exception e) {
            log.info("Результаты сканирования Авторизоватьсянеудача ticket:{}", ticket);
            return Response.<String>builder()
                    .code(Constants.ResponseCode.UN_ERROR.getCode())
                    .info(Constants.ResponseCode.UN_ERROR.getInfo())
                    .build();
        }
    }

}

Разработать два интерфейса;

  1. /api/v1/login/weixin_qrcode_ticket - получать Вичат ticket сертификат
  2. /api/v1/login/check_login - Проверка ротационного обучения Авторизоваться

4. Развитие публичного счета

Прежде всего, пока процесс разработки общедоступной учетной записи завершен, необходимо осуществить стыковку общедоступной учетной записи. Такая стыковка означает, что вы самостоятельно разрабатываете программу стыковки согласно официальным документам аккаунта и настраиваете ее под официальную платформу аккаунта.

4.1 Инструкции по настройке

Как показано на рисунке, это то, что вы увидите после входа в официальную платформу тестирования учетной записи WeChat и добавления конфигурации интерфейса и безопасного доменного имени JS.

  1. Вверху необходимо настроить номер Вичата xfg-dev-tech-weixin-login из application-dev.yml в файле.
  2. Информация о номере теста appID, appsecret также необходимо настроить на application-dev.yml в файле.
  3. интерфейсинформацияиз Конфигурация,Вы нужны для запуска xfg-dev-tech-weixin-login, при локальном тестировании запускать natapp проникновение в После интранет-инструмента. Используйте ваше изпроникновение в адрес интранета, и инженерно запросить адрес из URL Настроить на официальный интерфейс аккаунта. Проверка подписи будет произведена при настройке из. Если проверка подписи прошла успешно, настройка прошла успешно.
  4. Вам также необходимо отсканировать фокус наQR-код номера теста,Таким образом, вы можете увидеть тестинформация。
4.2 Сервис проверки подписи

Исходный код:cn.bugstack.xfg.dev.tech.trigger.http.WeixinPortalController

Язык кода:javascript
копировать
@Slf4j
@RestController()
@CrossOrigin("*")
@RequestMapping("/api/v1/weixin/portal/")
public class WeixinPortalController {

    @Value("${weixin.config.originalid}")
    private String originalid;
    @Resource
    private Cache<String, String> openidToken;

    /**
     * Проверка подписи, жесткое кодирование token b8b6 - Измените по мере необходимости
     */
    @GetMapping(value = "receive", produces = "text/plain;charset=utf-8")
    public String validate(@RequestParam(value = "signature", required = false) String signature,
                           @RequestParam(value = "timestamp", required = false) String timestamp,
                           @RequestParam(value = "nonce", required = false) String nonce,
                           @RequestParam(value = "echostr", required = false) String echostr) {
        try {
            log.info("Вичат Официальный начать проверку информации аккаунта [{}, {}, {}, {}]", signature, timestamp, nonce, echostr);
            if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) {
                throw new IllegalArgumentException("Параметр просить недопустим, пожалуйста, проверьте!");
            }
            boolean check = SignatureUtil.check("b8b6", signature, timestamp, nonce);
            log.info("Вичат Официальный Информация для проверки аккаунта заполнена. check:{}", check);
            if (!check) {
                return null;
            }
            return echostr;
        } catch (Exception e) {
            log.error("Вичат Официальный аккаунт Проверкаинформациянеудача [{}, {}, {}, {}]", signature, timestamp, nonce, echostr, e);
            return null;
        }
    }

    /**
     * Обратный звонок, получить Официальный сообщение аккаунта [Сканировать Авторизоваться, вы получите сообщение]
     */
    @PostMapping(value = "receive", produces = "application/xml; charset=UTF-8")
    public String post(@RequestBody String requestBody,
                       @RequestParam("signature") String signature,
                       @RequestParam("timestamp") String timestamp,
                       @RequestParam("nonce") String nonce,
                       @RequestParam("openid") String openid,
                       @RequestParam(name = "encrypt_type", required = false) String encType,
                       @RequestParam(name = "msg_signature", required = false) String msgSignature) {
        try {
            log.info("Получить Вичат Официальный аккаунтинформацияпросить{}начинать {}", openid, requestBody);
            // преобразование сообщений
            MessageTextEntity message = XmlUtil.xmlToBean(requestBody, MessageTextEntity.class);

            // Сканируйте код, чтобы введите【Тип сообщения】
            if ("event".equals(message.getMsgType()) && "SCAN".equals(message.getEvent())) {
                // Могут быть созданы реальные бизнес-сценарии jwt из token Позвольте фронтенду хранить
                openidToken.put(message.getTicket(), openid);
                return buildMessageTextEntity(openid, "Авторизоватьсяуспех");            }

            log.info("Получить Вичат Официальный аккаунтинформацияпросить{}Заканчивать {}", openid, requestBody);
            return buildMessageTextEntity(openid, «Чтобы проверить этот случай, спросите Сканируйте код, чтобы войти!");
        } catch (Exception e) {
            log.error("Получить Вичат Официальный аккаунтинформацияпросить{}неудача {}", openid, requestBody, e);
            return "";
        }
    }

    private String buildMessageTextEntity(String openid, String content) {
        MessageTextEntity res = new MessageTextEntity();
        // Официальный аккаунтраспространятьизID        res.setFromUserName(originalid);
        res.setToUserName(openid);
        res.setCreateTime(String.valueOf(System.currentTimeMillis() / 1000L));
        res.setMsgType("text");
        res.setContent(content);
        return XmlUtil.beanToXml(res);
    }

}
  • Подтвердите подпись и получите Официальный аккаунтперезвонить,является фиксированным из кода,в то же время Подтвердите подпись и получите Официальный обратные вызовы аккаунта также имеют одно и то же имя интерфейса, только одно get просить,кроме один есть post просить。Проверкаадрес:http://xfg-studio.natapp1.cc/api/v1/weixin/portal/receive Вам необходимо заменить ваше изпроникновение в адрес доменного имени интранета.
  • При получении Официального В обратном вызове аккаунта есть кусок исправленного кода. Получить официальный тип сообщения аккаунта — событие, тип события — скан-код (SCAN), который можно получить в ticket Это только сертификат.
  • проверять Авторизоватьсячас,Простая имитация записи вкэшсередина。openidToken.put(message.getTicket(), openid); Фактический бизнес-сценарий будет преобразован в Авторизоватьсяиз. jwt token данные.
4.3 Проникновение в интранет
  • Инструмент проникновения в интранет, купите платный туннель за 12 юаней. https://natapp.cn/
  • После покупки настройте локальный порт туннеля как 8091 Это твой местный SpringBoot программаизпорт。если ты не 8091 Порт, можно изменить на другой
  • Загрузка программного обеспечения, проникновение в для интранета требуется локальное программное обеспечение. Скачать можно с сайта itizweb-site. https://natapp.cn/#download Все версии также поддерживаются, а также имеются соответствующие учебные пособия по использованию.
  • После установки программного обеспечения запустите natapp и приложение, вы можете настроить свой адрес к нему.

4. Проверка функции

1. Запустите службу SpringBoot.

Язык кода:javascript
копировать
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::               (v2.7.12)
24-02-25.17:13:00.372 [main            ] INFO  EndpointLinksResolver  - Exposing 1 endpoint(s) beneath base path '/actuator'
24-02-25.17:13:00.405 [main            ] INFO  Http11NioProtocol      - Starting ProtocolHandler ["http-nio-8091"]
24-02-25.17:13:00.440 [main            ] INFO  TomcatWebServer        - Tomcat started on port(s): 8091 (http) with context path ''
24-02-25.17:13:00.461 [main            ] INFO  Application            - Started Application in 4.268 seconds (JVM running for 4.941)

2. Начать проникновение в интранет

  • от natapp.cn Ты в туннеле получаешь authtoken Настройте его в загруженном вами локальном программном обеспечении. [скачиваю версию изmac]
  • послеты Можетдвойной щелчокзапускать,также Можетпроходить./natapp запускать

3. Получите QR-код

3.1 Получите учетные данные билета

Интерфейс доступа: http://xfg-studio.natapp1.cc/api/v1/login/weixin_qrcode_ticket — нужно заменить на свой адрес.

3.2 Создать QR-код

Интерфейс доступа: http://xfg-studio.natapp1.cc/api/v1/login/check_login — нужно заменить на свой адрес.

4. Отсканируйте QR-код, чтобы войти в систему.

Используйте WeChat для сканирования QR-кода и просмотра журналов сервера и подсказок мобильного телефона.

Язык кода:javascript
копировать
24-02-25.17:25:09.096 [http-nio-8091-exec-3] INFO  LoginController        - генерировать Вичат Сканируйте код, чтобы войти ticket gQHN7zwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAycTRMbnB4TDBjckcxT043cjFCMWoAAgR1B9tlAwQ8AAAA
24-02-25.17:25:18.793 [http-nio-8091-exec-5] INFO  WeixinPortalController - Получить Вичат Официальный аккаунтинформацияпроситьor0Ab6ivwmypESVp_bYuk92T6SvUначинать <xml><ToUserName><![CDATA[gh_e067c267e056]]></ToUserName>
<FromUserName><![CDATA[or0Ab6ivwmypESVp_bYuk92T6SvU]]></FromUserName>
<CreateTime>1708853118</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[SCAN]]></Event>
<EventKey><![CDATA[100601]]></EventKey>
<Ticket><![CDATA[gQHN7zwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAycTRMbnB4TDBjckcxT043cjFCMWoAAgR1B9tlAwQ8AAAA]]></Ticket>
</xml>
  • Сканируйте код, чтобы войтиназад,Можетпосмотреть отзывизсостояниеинформацияа также Служитьконецизбревно。

5. Имитация входа в систему по циклу

  • Интерфейс доступа: http://xfg-studio.natapp1.cc/api/v1/login/check_login — нужно заменить на свой адрес.
  • хороший,Это показывает, что Авторизация прошла успешно.,и вернутьсяopenidинформация。Собственныйизбизнес-сценарий,Возможен возврат токена Сохранить в браузере.
boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose