D
D
Dmitry Bayov2017-05-14 11:02:22
Java
Dmitry Bayov, 2017-05-14 11:02:22

Direct authorization of the VK application, how to do?

Hello!

There is a desktop application that authorizes the VKontakte user. Through trial and error in the ending, I came to this authorization option (receiving ACCESS_TOKEN)

In this method, we follow a link that will ask whether to give this application access?

We take hashes from the page: ip_h, lg_h, to.
They are needed to send a POST request for authorization.

Along the way, we pull out the "remixlhk" cookie, without which VK does not even want to say hello.

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();
    }


Next, we send a POST request for authorization.
From the response page we take a link to confirm access to the application ...
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];
            }
        }
    }


... and we pass through it, passing the cookie.
From the URL of the response page, we get the token and user ID.
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]);
    }


Well, here we create a user to access the VK API (which will be used further) and get his name to greet.
private void getVkFirstNameCurrentUser() throws IOException, ClientException, ApiException {
        actor = new UserActor(vk_id, ACCESS_TOKEN);

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


Actually a problem. Even two.

1. Almost always, authorization passes only the second time, an error pops up when trying to authorize, that is, when receiving a link from method 2 (fullAuthorization). Sometimes it goes away the first time, sometimes only the second. A third time is never required. If the first time did not pass, I close the error and repeat the authorization attempt. Everything works out. Any ideas what could be the problem?

2. The most stupid problem, just magic. Of course, I believe in magic, but maybe someone will have an idea how this magic works?
I use JavaFX for the GUI. There is an FXML file with the following content.
<?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>


Pay attention to the WebView element almost at the very end. Initially, authorization was by opening a WebView in the application, but I wanted to do direct authorization. Still more beautiful.
While doing, WebView was in place, after everything worked out (authorization), I began to clean the code and removed WebView. Everything is broken. He does not want to log in, says the password is incorrect.

Removed all references to WebView from the code, remained only in the FXML file. It is not used anywhere else. Its dimensions are 0.1 by 0.1. But without it, authorization does not work at all.

Any ideas how to disenchant the princess?

Answer the question

In order to leave comments, you need to log in

1 answer(s)
K
kekenec, 2017-05-18
@SonnySP

If you do not have to conjure over parsers and it is possible not to use your own application (the one that you created in VK), then there is an easier option - use the client_id and client_secret of the official VK applications for mobile devices. All data can be found here . Next, send a GET request:
In response, get access_token, expires_in and user_id in JSON format.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question