Сервер отвергает запрос

Всем привет! Пытался сделать программу, которая будет выполнять логин в электронный дневник по NetSchoolAPI. Вот мой код:

import com.fasterxml.jackson.databind.ObjectMapper;
import me.theentropyshard.netschoolapi.dto.AuthDataObject;
import me.theentropyshard.netschoolapi.dto.GetDataObject;
import me.theentropyshard.netschoolapi.dto.SchoolDataObject;
import org.apache.http.client.CookieStore;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;

public class NetschoolAPI {
    private static final Logger log = Logger.getLogger();

    private final String username;
    private final String password;
    private final String schoolName;

    private final CloseableHttpClient httpClient;
    private final HttpClientContext clientContext;
    private final CookieStore cookieStore;
    private final ObjectMapper objectMapper;

    private int cid;
    /**
     * countryId
     */
    private int sid;
    /**
     * stateId
     */
    private int pid;
    /**
     * municipalityDistrictId
     */
    private int cn;
    /**
     * cityId
     */
    private int sft;
    /**
     * funcType (school function type)
     */
    private int scid;

    /**
     * id (school id)
     */

    public NetschoolAPI(String username, String password, String schoolName) {
        this.username = username;
        this.password = password;
        this.schoolName = schoolName;

        this.cookieStore = new BasicCookieStore();
        this.httpClient = HttpClients.custom()
                .setDefaultCookieStore(this.cookieStore)
                .build();
        this.clientContext = HttpClientContext.create();
        this.clientContext.setAttribute(HttpClientContext.COOKIE_STORE, this.cookieStore);
        this.objectMapper = new ObjectMapper();

        this.init();
    }

    private void init() {
        log.info("Looking for schools...");
        try {
            HttpGet httpGet = new HttpGet(Constants.SCHOOLS_URL);
            CloseableHttpResponse response = httpClient.execute(httpGet);
            if(response == null) {
                throw new RuntimeException("Http Response for " + Constants.SCHOOLS_URL + " is null");
            }
            SchoolDataObject[] schoolDataObjects = this.objectMapper.readValue(response.getEntity().getContent(), SchoolDataObject[].class);
            for(SchoolDataObject schoolDataObject : schoolDataObjects) {
                if(schoolDataObject != null) {
                    if(schoolDataObject.name.equals(this.schoolName)) {
                        log.info("Found school \"" + this.schoolName + "\"");
                        this.cid = schoolDataObject.countryId;
                        this.sid = schoolDataObject.stateId;
                        this.pid = schoolDataObject.municipalityDistrictId;
                        this.cn = schoolDataObject.cityId;
                        this.sft = schoolDataObject.funcType;
                        this.scid = schoolDataObject.id;
                        break;
                    }
                }
            }
        } catch (IOException e) {
            throw new RuntimeException("Could not get schools data");
        }
    }

    public void login() {
        log.info("Trying to login...");

        try {
            HttpPost httpPost = new HttpPost(Constants.LOGIN_URL);
            AuthDataObject authData = this.getAuthData();
            String requestString = this.getRequestString(authData);
            httpPost.setEntity(new StringEntity(requestString));

            httpPost.setHeader("Accept", "application/json, text/javascript, */*; q=0.01");
            httpPost.setHeader("Accept-Encoding", "gzip, deflate, br");
            httpPost.setHeader("Accept-Language", "ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7");
            //x-www-form-urlencoded
            httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
            try(CloseableHttpResponse response = httpClient.execute(httpPost, this.clientContext)) {
                log.info(new Scanner(response.getEntity().getContent()).nextLine());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        log.info("Successfully logged in!");
    }

    private AuthDataObject getAuthData() {
        log.info("Trying to get auth data...");

        System.out.println(this.clientContext.getCookieStore().getCookies());
        this.fetchLogindata();
        System.out.println(this.clientContext.getCookieStore().getCookies());

        AuthDataObject authDataObject;
        HttpPost httpPost = new HttpPost(Constants.GET_DATA_URL);
        httpPost.setHeader("Accept", "application/json, text/javascript, */*; q=0.01");
        httpPost.setHeader("Accept-Encoding", "gzip, deflate, br");
        httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        try {
            GetDataObject getDataObject;
            try(CloseableHttpResponse response = httpClient.execute(httpPost, this.clientContext)) {
                getDataObject = objectMapper.readValue(response.getEntity().getContent(), GetDataObject.class);
            }
            String encodedPassword = Utils.md5(this.password.getBytes(Charset.forName("windows-1251")));
            String pw2 = Utils.md5((getDataObject.salt + encodedPassword).getBytes(StandardCharsets.UTF_8));
            String pw = pw2.substring(0, this.password.length());
            authDataObject = new AuthDataObject(pw, pw2, getDataObject.lt, getDataObject.ver);
        } catch (IOException e) {
            throw new RuntimeException("Could not get auth data");
        } catch (NullPointerException e) {
            throw new RuntimeException("Internal error", e);
        }

        System.out.println(this.clientContext.getCookieStore().getCookies());
        log.info("Successfully got auth data");

        return authDataObject;
    }

    private void fetchLogindata() {
        HttpGet httpGet = new HttpGet(Constants.LOGINDATA_URL);
        httpGet.setHeader("Accept", "application/json, text/javascript, */*; q=0.01");
        httpGet.setHeader("Accept-Encoding", "gzip, deflate, br");
        httpGet.setHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        try(CloseableHttpResponse response = httpClient.execute(httpGet, this.clientContext)) {
            System.out.println(new Scanner(response.getEntity().getContent()).nextLine());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void logout() {
        log.info("Trying to log out...");
        try {
            HttpPost httpGet = new HttpPost(Constants.LOGOUT_URL);
            try(CloseableHttpResponse response = httpClient.execute(httpGet)) {

            }
        } catch (IOException e) {
            e.printStackTrace();
            return;
        }
        log.info("Successfully logged out!");
    }

    private String getRequestString(AuthDataObject ado) {
        return String.format("LoginType=1&cid=%d&sid=%d&pid=%d&cn=%d&sft=%d&scid=%d&UN=%s&PW=%s&lt=%s&pw2=%s&ver=%s",
                this.cid, this.sid, this.pid, this.cn, this.sft, this.scid, Utils.urlEncode(this.username, "UTF-8"),
                ado.pw, ado.lt, ado.pw2, ado.ver);
    }
}

Вот код из класса Constants:

public static final String BASE_URL = "https://giseo.rkomi.ru/";
public static final String WEBAPI_URL = BASE_URL + "webapi/";
public static final String LOGINDATA_URL = WEBAPI_URL + "logindata";
public static final String GET_DATA_URL = WEBAPI_URL + "auth/getdata";
public static final String LOGIN_URL =  WEBAPI_URL + "login";
public static final String SCHOOLS_URL = WEBAPI_URL + "addresses/schools";
public static final String LOGOUT_URL =  WEBAPI_URL + "auth/logout";

Получаю ошибку 409 - Conflict. В ответе JSON с сообщением "Ошибка входа в систему", если же я уберу параметр LoginType, то получаю уже ответ, что этот самый параметр не найден, то есть, сервер понимает, что я ему отправляю, но пускать меня не хочет. Использую в качестве HTTP клиента вот это:

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.13</version>
</dependency>

Есть вот такой репозиторий - https://github.com/nm17/netschoolapi, если я ввожу туда свои данные, то он работает, вход в систему выполняется. Классы из пакета dto это простые обертки для JSON'a. Кратко, как это должно работать:

  • Отправляем POST на /webapi/auth/getdata, откуда получаем lt, ver, salt.
  • Хэшируем пароль с помощью salt
  • Отправляем POST на /webapi/login с типом контента url encoded. Туда и добавляем lt и ver
  • В ответе получаем заголовок at, который является своеобразным ключом сессии(простите, если неправильно назвал), с помощью него производим дальнейшие операции в системе. Подскажите пожалуйста, что делаю не так. Простите за такой длинный вопрос, более кратко описать суть проблемы сложно.

EDIT: Вообщем, насчет той репы, я попробовал вывести ответ с httpbin у себя и у этого пайтон проекта - у меня имя пользователя превратилось в \uXXXX подобный набор символов, а в пайтоне - вернулось в таком же виде. (Имя пользователя на русском). Как я понял, проблема в кодировке, что делать?


Ответы (1 шт):

Автор решения: TheEntropyShard

Вообщем... Всего то нужно было добавить пару заголовков в запрос, которые я считал "необязательными", а именно вот эти:

httpPost.setHeader("X-Requested-With", "XMLHttpRequest");
httpPost.setHeader("Referer", Constants.BASE_URL);

(добавил в логин запрос)
→ Ссылка