Задать вопрос
SonnySP
@SonnySP
Very Junior Java

Прямая авторизация приложения VK, как сделать?

Здравствуйте!

Есть desktop приложение, которое авторизует пользователя вконтакте. Путём проб и ошибок в оконцовке пришёл к такому варианту авторизации(получение ACCESS_TOKEN)

В этом методе мы проходим по ссылке, которая будет спрашивать, дать ли этому приложению доступ?

Берём со страницы хэши: ip_h, lg_h, to.
Они нужны для отправки POST запроса на авторизацию.

Попутно вытягиваем печеньку "remixlhk", без которого ВК не хочет даже здороваться.
private void getCookieremixlhk() throws IOException {
        URL url = new URL("https://oauth.vk.com/authorize?client_id=id_вашей_группыredirect_uri=https://oauth.vk.com/blank.html&scope=friends,groups&response_type=token&revoke=1");
        ArrayList<String> listHeaders = new ArrayList<>();
        HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();

        for (Map.Entry<String, List<String>> pair : conn.getHeaderFields().entrySet()) {
            listHeaders.addAll(pair.getValue());
        }

        for (String listi : listHeaders) {
            if (listi.contains("remixlhk")) {
                remixlhk = listi.split("=", 2)[1].split(";", 2)[0];
            }
        }

        BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));

        while (in.ready()) {
            String temp = in.readLine();
            if (temp.contains("ip_h"))
                ip_h = temp.split("value=\"", 2)[1].split("\"")[0];
            if (temp.contains("lg_h"))
                lg_h = temp.split("value=\"", 2)[1].split("\"")[0];
            if (temp.contains("name=\"to\""))
                to = temp.split("value=\"", 2)[1].split("\"")[0];
        }

        in.close();
    }


Дальше мы отправляем POST запрос на авторизацию.
Из страницы ответа берём ссылку на подтверждение доступа приложению...
private void fullAuthorization() throws IOException {
        URL url = new URL("https://login.vk.com/?act=login&soft=1");
        Map<String, Object> params = new LinkedHashMap<>();

        params.put("_origin", "https://oauth.vk.com");
        params.put("email", email);
        params.put("expire", "0");
        params.put("ip_h", ip_h);
        params.put("lg_h", lg_h);
        params.put("pass", pass);
        params.put("to", to);
        params.put("Cookie", "remixlhk="+remixlhk);

        StringBuilder postData = new StringBuilder();
        for (Map.Entry<String, Object> param : params.entrySet()) {
            if (postData.length() != 0) postData.append('&');
            postData.append(URLEncoder.encode(param.getKey(), "UTF-8"));
            postData.append('=');
            postData.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8"));
        }
        byte[] postDataBytes = postData.toString().getBytes("UTF-8");

        HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        conn.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length));
        conn.setDoOutput(true);

        conn.getOutputStream().write(postDataBytes);

        BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
        while (in.ready()) {
            String temp = in.readLine();
            if (temp.contains("grant_access")) {
                linkAccept = temp.split("form method=\"post\" action=\"")[1].split("\"", 2)[0];
            }
        }
    }


... и проходим по ней, передав печеньку.
Из URL страницы ответа получаем токен и айди пользователя.
private void acceptAndGetToken() throws IOException {
        URL url = new URL(linkAccept);
        Map<String, Object> params = new LinkedHashMap<>();
        params.put("Cookie", "remixlhk="+remixlhk);

        StringBuilder postData = new StringBuilder();
        for (Map.Entry<String, Object> param : params.entrySet()) {
            if (postData.length() != 0) postData.append('&');
            postData.append(URLEncoder.encode(param.getKey(), "UTF-8"));
            postData.append('=');
            postData.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8"));
        }
        byte[] postDataBytes = postData.toString().getBytes("UTF-8");

        HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        conn.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length));
        conn.setDoOutput(true);

        BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));

        String URL = conn.getURL().toString();

        ACCESS_TOKEN = URL.split("token=", 2)[1].split("&", 2)[0];
        vk_id = Integer.valueOf(URL.split("user_id=", 2)[1]);
    }


Ну тут создаем пользователя для обращения к VK API(которое будет использоваться и дальше) и достаём его имя, чтобы поприветствовать.
private void getVkFirstNameCurrentUser() throws IOException, ClientException, ApiException {
        actor = new UserActor(vk_id, ACCESS_TOKEN);

        vkFirstName = vkApiClient.account().getProfileInfo(actor).execute().getFirstName();
    }


Собственно проблема. Даже две.

1. Практически всегда авторизация проходит только со второго раза, ошибка выскакивает при попытке авторизации, то есть при получении ссылки из метода 2(fullAuthorization). Бывает, что проходит с первого раза, бывает только со второго. Третий раз никогда не требуется. Если первый раз не прошло, закрываю ошибку и повторяю попытку авторизации. Всё получается. Есть идеи, в чём может быть проблема?

2. Самая тупая проблема, просто магия. Я, конечно, в магию верю, но может у кого нибудь будет идея, как эта магия работает?
Для GUI использую JavaFX. Есть FXML файл следующего содержания.
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.Font?>
<?import javafx.scene.web.WebView?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="260.0" prefWidth="296.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="mainpackage.view.login.LoginPageController">
    <children>
        <ButtonBar layoutX="5.0" layoutY="209.0" prefHeight="40.0" prefWidth="246.0" AnchorPane.bottomAnchor="11.0" AnchorPane.rightAnchor="26.0">
            <buttons>
                <Button mnemonicParsing="false" onAction="#handleOkButtonClicked" text="OK" />
                <Button mnemonicParsing="false" onAction="#handleCancelButtonClicked" text="Cancel" />
                <Button mnemonicParsing="false" onAction="#handleNoAuthButtonClicked" text="No Auth" />
            </buttons>
        </ButtonBar>
        <TextField fx:id="loginTextField" layoutX="26.0" layoutY="67.0" prefHeight="25.0" prefWidth="246.0" />
        <Label layoutX="28.0" layoutY="42.0" text="Login" />
        <Label layoutX="28.0" layoutY="109.0" text="Password" />
        <Label layoutX="32.0" layoutY="14.0" prefWidth="153.0" text="Authorization on VK.com" AnchorPane.leftAnchor="70.0" AnchorPane.rightAnchor="70.0" AnchorPane.topAnchor="10.0">
            <font>
                <Font name="Arial Bold" size="12.0" />
            </font>
        </Label>
        <PasswordField fx:id="passwordTextField" layoutX="26.0" layoutY="135.0" prefHeight="25.0" prefWidth="246.0" />
        <WebView fx:id="webViewOnLogin" prefHeight="0.1" prefWidth="0.1" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
      <Label fx:id="textAfterAuthorization" alignment="CENTER" contentDisplay="CENTER" layoutX="27.0" layoutY="177.0" prefHeight="17.0" prefWidth="246.0" text="Авторизация занимает 5-10 секунд" />
    </children>
</AnchorPane>


Обратите внимание на элемент WebView практически в самом конце. Изначально авторизация была путём открывания WebView в приложении, но захотелось сделать прямую авторизацию. Красивше всё таки.
Пока делал, WebView был на месте, после того, как все получилось(авторизация), стал чистить код и удалил WebView. Всё сломалось. Не хочет он логиниться, говорит, пароль неверный.

Убрал все упоминания WebView из кода, остался только в FXML файле. Он больше нигде не используется. Размеры его 0.1 на 0.1. Но без него авторизация не работает совершенно.

Есть идеи, как можно расколдовать принцессу?
  • Вопрос задан
  • 5706 просмотров
Подписаться 8 Оценить Комментировать
Решения вопроса 1
@kekenec
Если вам не обязательно колдовать над парсерами и есть возможность не использовать собственное приложение (то, которые вы создавали в ВК), то есть вариант проще - использовать client_id и client_secret официальных приложений ВК для мобильных устройств. Все данные можно найти здесь. Далее отправляете GET запрос:
https://oauth.vk.com/token?grant_type=password&client_id=*&client_secret=*&username=*&password=*&scope=*

В ответе получите access_token, expires_in и user_id в формате JSON.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы